feat: improved nth roots

This commit is contained in:
newt 2024-10-09 18:02:44 +01:00
parent 5f9fdcdc3b
commit 4be3f7191e
7 changed files with 157 additions and 43 deletions

12
.vscode/settings.json vendored
View file

@ -23,6 +23,16 @@
"tuple": "cpp", "tuple": "cpp",
"type_traits": "cpp", "type_traits": "cpp",
"string_view": "cpp", "string_view": "cpp",
"vector": "cpp" "vector": "cpp",
"algorithm": "cpp",
"memory": "cpp",
"random": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"numeric": "cpp",
"ostream": "cpp",
"ratio": "cpp",
"streambuf": "cpp"
} }
} }

View file

@ -2,39 +2,104 @@
#include <cmath> #include <cmath>
#include <limits> #include <limits>
double nthRoot(double n, double x) { std::string superscript[10] = { "", "¹", "²", "³", "", "", "", "", "", "" };
double lastX;
double y = 1; // initial guess
while (y != lastX) { struct Result {
// f(y) = yⁿ - x double result;
// f'(y) = nyⁿ⁻¹ int maxIterations;
double f = std::pow(y, n) - x; int iterationsUsed;
double fprime = n * std::pow(y, n - 1); };
lastX = y; // See https://github.com/newtykins/the-honk/tree/main/maths/nth%20root.png
y -= f / fprime; Result nthRoot(double n, double x, int maxIterations = 200) {
Result output;
output.result = 1;
output.maxIterations = maxIterations;
output.iterationsUsed = 0;
double lastIteration = 0;
for (int i = 0; i < maxIterations; i++) {
if (lastIteration == output.result) {
break;
}
output.iterationsUsed += 1;
lastIteration = output.result;
output.result = ((lastIteration * (n - 1)) + (x * std::pow(lastIteration, 1 - n))) / n;
} }
return y; return output;
} }
int promptForInteger(std::string letter) { int fetchInput(std::string letter) {
std::cout << "Please input a value for " + letter + ": "; std::cout << "Please input a value for " + letter + ": ";
int input; double input;
std::cin >> input; std::cin >> input;
return input; return input;
} }
bool isInt(double n) {
return (int) n == n;
}
std::string formatDouble(double input) {
std::string str = std::to_string(input);
str.erase(str.find_last_not_of('0') + 1, std::string::npos);
return str;
}
std::string formatRadical(double n, double x) {
std::string formattedN = "";
std::string formattedX = "";
if (isInt(n)) {
std::string nString = std::to_string((int) n);
for (int i = 0; i < nString.length(); i++) {
int digit = (int) nString[i] - 48;
formattedN += superscript[digit];
}
} else {
std::string nString = formatDouble(n);
for (int i = 0; i < nString.length(); i++) {
try {
int digit = (int) nString[i] - 48;
formattedN += superscript[digit];
} catch (const std::exception) {
formattedN += "˙";
}
}
}
if (isInt(x)) {
formattedX = std::to_string((int) x);
} else {
formattedX = formatDouble(x);
}
return formattedN + "" + formattedX;
}
int main() { int main() {
std::cout << "ⁿ√x\n"; std::cout << "ⁿ√x\n";
int n = promptForInteger("n");
int x = promptForInteger("x"); double n = fetchInput("n");
double x = fetchInput("x");
std::cout << "Please enter an amount of iterations to perform: ";
int iterations;
std::cin >> iterations;
// Make sure that cout prints to the highest precision possible // Make sure that cout prints to the highest precision possible
std::cout.precision(std::numeric_limits<double>::max_digits10); std::cout.precision(std::numeric_limits<double>::max_digits10);
std::cout << nthRoot(n, x);
Result root = nthRoot(n, x, iterations);
std::cout << "\n" << formatRadical(n, x) << " = " << root.result << "\n";
std::cout << "Used " << root.iterationsUsed << " out of " << root.maxIterations << " iterations (:";
} }

View file

@ -44,17 +44,9 @@ std::string formatFraction(int numerator, int denominator) {
// Format a double by cutting off as many trailing zeros as possible // Format a double by cutting off as many trailing zeros as possible
std::string formatDouble(double input) { std::string formatDouble(double input) {
std::string output = std::to_string(abs(input)); std::string str = std::to_string(input);
int pointIndex = output.find_last_of('.'); str.erase(str.find_last_not_of('0') + 1, std::string::npos);
int firstZeroIndex = output.find_last_not_of('0') + 1; return str;
if (firstZeroIndex - 1 == pointIndex) {
output.erase(firstZeroIndex - 1, std::string::npos);
} else {
output.erase(firstZeroIndex, std::string::npos);
}
return output;
} }
// ax² + b^x + c^x -> a(x + p) + q // ax² + b^x + c^x -> a(x + p) + q

View file

@ -2,7 +2,7 @@
def floatInput(text): def floatInput(text):
while True: while True:
try: try:
x = float(input(text + '\n')) x = float(input(text))
return x return x
except ValueError: except ValueError:
print('You must input a float integer!\n') print('You must input a float integer!\n')

View file

@ -2,7 +2,7 @@
def intInput(text): def intInput(text):
while True: while True:
try: try:
x = int(input(text + '\n')) x = int(input(text))
return x return x
except ValueError: except ValueError:
print('You must input an integer!\n') print('You must input an integer!\n')

View file

@ -1,16 +1,63 @@
def nthRoot(n: int, x: int): from typing import Union
lastX = None from _helpers import floatInput, intInput
y = 1 # initial guess from dataclasses import dataclass
while y != lastX: @dataclass
# f(y) = yⁿ - x class Result:
# f'(y) = nyⁿ⁻¹ result: Union[float, int]
f = (y ** n) - x maxIterations: int
fprime = n * (y ** (n - 1)) iterationsUsed: int
lastX = y
y -= f / fprime
return y superscript = [ '', '¹', '²', '³', '', '', '', '', '', '' ]
print(nthRoot(5, 6 ** 6)) def formatRadical(n: float, x: float):
formattedN, formattedX = '', ''
if int(n) == n:
nString = str(int(n))
for i in range(len(nString)):
digit = int(nString[i])
formattedN += superscript[digit]
else:
nString = str(n)
for i in range(len(nString)):
try:
digit = int(nString[i])
formattedN += superscript[digit]
except:
formattedN += '˙'
if int(x) == x:
formattedX = str(int(x))
else:
formattedX = str(x)
return f"{formattedN}{formattedX}"
def nthRoot(n: float, x: float, maxIterations: int = 200) -> Result:
lastIteration, iteration, iterationsUsed = 0, 1, 0
for _ in range(maxIterations):
if lastIteration == iteration:
break
iterationsUsed += 1
lastIteration = iteration
iteration = ((iteration * (n - 1)) + (x * (iteration ** (1 - n)))) / n
if int(iteration) == iteration:
iteration = int(iteration)
return Result(iteration, maxIterations, iterationsUsed)
print('ⁿ√x')
n = floatInput('Please input a value for n: ')
x = floatInput('Please input a value for x: ')
iterations = intInput('Please enter an amount of iterations to perform: ')
root = nthRoot(n, x, iterations)
print(f'\n{formatRadical(n, x)} = {root.result}')
print(f'Used {root.iterationsUsed} out of {root.maxIterations} iterations (:')

BIN
maths/nth root.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 293 KiB