feat: improved nth roots
This commit is contained in:
parent
5f9fdcdc3b
commit
4be3f7191e
7 changed files with 157 additions and 43 deletions
12
.vscode/settings.json
vendored
12
.vscode/settings.json
vendored
|
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 (:";
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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')
|
||||||
|
|
|
@ -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')
|
||||||
|
|
|
@ -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
BIN
maths/nth root.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 293 KiB |
Loading…
Reference in a new issue