Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * This program calculates nth roots as well as a^b for
- * (probably) any positive value of b, including values like 3.1
- * SE Answer where I wrote it:
- * https://math.stackexchange.com/a/2995982/272911
- */
- #include <stdio.h>
- #include <float.h>
- #define PRECISION 20
- #define MAX(a, b) \
- ( (a) > (b) ? (a) : (b) )
- #define MIN(a, b) \
- ( (a) < (b) ? (a) : (b) )
- #define GET_INT(n) \
- ( (double)((int)(n)) )
- #define GET_DEC(n) \
- ( (n) - GET_INT(n) )
- #define IS_INT(n) \
- ( MAX((n), GET_INT(n)) - MIN((n), GET_INT(n)) <= FLT_EPSILON )
- int *dec_to_frac(double);
- int get_numer(double);
- int get_denom(double);
- double fpow(double, double);
- double ipow(double, int);
- double root(int exp, double x);
- // takes floating point x and returns an integer array {numerator, denominator}
- // dec_to_frac(5.4) -> {54, 10}
- int *
- dec_to_frac(double x)
- {
- int magnitude = 1;
- static int ret[2];
- while(IS_INT(x) == 0){
- x *= 10;
- magnitude *= 10;
- }
- ret[0] = (int)x;
- ret[1] = magnitude;
- return ret;
- }
- // get_numer(5.4) -> 54
- int
- get_numer(double x)
- {
- return (dec_to_frac(x))[0];
- }
- // get_denom(5.4) -> 10
- int
- get_denom(double x)
- {
- return (dec_to_frac(x))[1];
- }
- // raise floating point a to floating point b
- // fpow(2.0, 3.1) -> 8.57418770029
- double
- fpow(double a, double b)
- {
- double bi;
- double bf;
- if(IS_INT(b))
- return ipow(a, (int)b);
- bi = GET_INT(b);
- bf = GET_DEC(b);
- return ipow(a, (int)bi) * root( get_denom(bf), ipow(a, get_numer(bf)) );
- }
- // raise floating point a to integer b
- // ipow(2.0, 3) -> 8.0
- double
- ipow(double a, int b)
- {
- double total = 1.0;
- while(b--)
- total *= a;
- return total;
- }
- // calculates the (exp)th root of x.
- // See the StackExchange link for an explanation (written by yours truly) of the calculus behind this.
- // root(3, 3.0) -> 1.44224957031
- double
- root(int exp, double x)
- {
- double guess = MAX(1.0, x / exp);
- for(int i = 0; i < PRECISION; i++)
- guess -= (ipow(guess, exp) - x) / ( exp * ipow(guess, exp - 1) );
- return guess;
- }
- // Testing everything
- int
- main(int argc, char **argv)
- {
- printf("pow(2, 3) = %.1f\n", fpow(2.0, 3.0));
- printf("pow(2, 3.1) = %.15f\n", fpow(2.0, 3.1));
- printf("root(2, 2) = %.15lf\n", root(2, 2.0));
- printf("root(3, 3) = %.15lf\n", root(3, 3.0));
- printf("root(2, 9) = %.15lf\n", root(2, 9.0));
- printf("root(4, 81) = %.15lf\n", root(4, 81.0));
- printf("--\n");
- printf("numer(0.1) = %i\n", get_numer(0.1));
- printf("denom(0.1) = %i\n", get_denom(0.1));
- printf("GET_DEC(3.1) = %0.35f\n", GET_DEC(3.1)); // and here you can see why (GET_DEC(3.1) == 0.1) is false
- printf("numer(GET_DEC(3.1)) = %i\n", get_numer(GET_DEC(3.1)));
- printf("denom(GET_DEC(3.1)) = %i\n", get_denom(GET_DEC(3.1)));
- printf("pow(2, 3.1) = %.15f\n", fpow(2.0, 3.1));
- printf("root(2, 2) = %.15lf\n", root(2, 2.0));
- printf("root(3, 3) = %.15lf\n", root(3, 3.0));
- printf("root(2, 9) = %.15lf\n", root(2, 9.0));
- printf("root(4, 81) = %.15lf\n", root(4, 81.0));
- // The only difference between the below method of 2^3.1 and the fpow() method is that
- // fpow()'s job is to automate the transition from `2^3.1` to `2^3 * root(10, 2^1)`
- // which is tricky because of the way floats work. (see 'GET_DEC(3.1) to 35 decimal places printout')
- printf("2^3.1 = 2^3 * 2^0.1\n");
- printf("8 * 2^(1/10) = 8 * root(10, 2)\n");
- printf("root(10, 2) = %.15lf\n", root(10, 2.0));
- printf("8 * root(10, 2) = %.15lf\n", 8 * root(10, 2.0));
- }
- /* output:
- * pow(2, 3) = 8.0
- * pow(2, 3.1) = 8.574187700290345
- * root(2, 2) = 1.414213562373095
- * root(3, 3) = 1.442249570307408
- * root(2, 9) = 3.000000000000000
- * root(4, 81) = 3.000000000000000
- * --
- * numer(0.1) = 1
- * denom(0.1) = 10
- * GET_DEC(3.1) = 0.10000000000000008881784197001252323
- * numer(GET_DEC(3.1)) = 1
- * denom(GET_DEC(3.1)) = 10
- * pow(2, 3.1) = 8.574187700290345
- * root(2, 2) = 1.414213562373095
- * root(3, 3) = 1.442249570307408
- * root(2, 9) = 3.000000000000000
- * root(4, 81) = 3.000000000000000
- * 2^3.1 = 2^3 * 2^0.1
- * 8 * 2^(1/10) = 8 * root(10, 2)
- * root(10, 2) = 1.071773462536293
- * 8 * root(10, 2) = 8.574187700290345
- */
Add Comment
Please, Sign In to add comment