B1KMusic

nth root calculator

Nov 20th, 2018
216
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 4.29 KB | None | 0 0
  1. /*
  2.  * This program calculates nth roots as well as a^b for
  3.  * (probably) any positive value of b, including values like 3.1
  4.  * SE Answer where I wrote it:
  5.  *     https://math.stackexchange.com/a/2995982/272911
  6.  */
  7.  
  8. #include <stdio.h>
  9. #include <float.h>
  10.  
  11. #define PRECISION 20
  12.  
  13. #define MAX(a, b) \
  14.     ( (a) > (b) ? (a) : (b) )
  15.  
  16. #define MIN(a, b) \
  17.     ( (a) < (b) ? (a) : (b) )
  18.  
  19. #define GET_INT(n) \
  20.     ( (double)((int)(n)) )
  21.  
  22. #define GET_DEC(n) \
  23.     ( (n) - GET_INT(n) )
  24.  
  25. #define IS_INT(n) \
  26.     ( MAX((n), GET_INT(n)) - MIN((n), GET_INT(n)) <= FLT_EPSILON )
  27.  
  28. int *dec_to_frac(double);
  29. int get_numer(double);
  30. int get_denom(double);
  31. double fpow(double, double);
  32. double ipow(double, int);
  33. double root(int exp, double x);
  34.  
  35. // takes floating point x and returns an integer array {numerator, denominator}
  36. // dec_to_frac(5.4) -> {54, 10}
  37. int *
  38. dec_to_frac(double x)
  39. {
  40.     int magnitude = 1;
  41.     static int ret[2];
  42.  
  43.     while(IS_INT(x) == 0){
  44.         x *= 10;
  45.         magnitude *= 10;
  46.     }
  47.  
  48.     ret[0] = (int)x;
  49.     ret[1] = magnitude;
  50.     return ret;
  51. }
  52.  
  53. // get_numer(5.4) -> 54
  54. int
  55. get_numer(double x)
  56. {
  57.     return (dec_to_frac(x))[0];
  58. }
  59.  
  60. // get_denom(5.4) -> 10
  61. int
  62. get_denom(double x)
  63. {
  64.     return (dec_to_frac(x))[1];
  65. }
  66.  
  67. // raise floating point a to floating point b
  68. // fpow(2.0, 3.1) -> 8.57418770029
  69. double
  70. fpow(double a, double b)
  71. {
  72.     double bi;
  73.     double bf;
  74.  
  75.     if(IS_INT(b))
  76.         return ipow(a, (int)b);
  77.  
  78.     bi = GET_INT(b);
  79.     bf = GET_DEC(b);
  80.  
  81.     return ipow(a, (int)bi) * root( get_denom(bf), ipow(a, get_numer(bf)) );
  82. }
  83.  
  84. // raise floating point a to integer b
  85. // ipow(2.0, 3) -> 8.0
  86. double
  87. ipow(double a, int b)
  88. {
  89.     double total = 1.0;
  90.  
  91.     while(b--)
  92.         total *= a;
  93.  
  94.     return total;
  95. }
  96.  
  97. // calculates the (exp)th root of x.
  98. // See the StackExchange link for an explanation (written by yours truly) of the calculus behind this.
  99. // root(3, 3.0) -> 1.44224957031
  100. double
  101. root(int exp, double x)
  102. {
  103.     double guess = MAX(1.0, x / exp);
  104.  
  105.     for(int i = 0; i < PRECISION; i++)
  106.         guess -= (ipow(guess, exp) - x) / ( exp * ipow(guess, exp - 1) );
  107.  
  108.     return guess;
  109. }
  110.  
  111. // Testing everything
  112. int
  113. main(int argc, char **argv)
  114. {
  115.     printf("pow(2, 3) = %.1f\n", fpow(2.0, 3.0));
  116.     printf("pow(2, 3.1) = %.15f\n", fpow(2.0, 3.1));
  117.     printf("root(2, 2) = %.15lf\n", root(2, 2.0));
  118.     printf("root(3, 3) = %.15lf\n", root(3, 3.0));
  119.     printf("root(2, 9) = %.15lf\n", root(2, 9.0));
  120.     printf("root(4, 81) = %.15lf\n", root(4, 81.0));
  121.     printf("--\n");
  122.     printf("numer(0.1) = %i\n", get_numer(0.1));
  123.     printf("denom(0.1) = %i\n", get_denom(0.1));
  124.     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
  125.     printf("numer(GET_DEC(3.1)) = %i\n", get_numer(GET_DEC(3.1)));
  126.     printf("denom(GET_DEC(3.1)) = %i\n", get_denom(GET_DEC(3.1)));
  127.     printf("pow(2, 3.1) = %.15f\n", fpow(2.0, 3.1));
  128.     printf("root(2, 2) = %.15lf\n", root(2, 2.0));
  129.     printf("root(3, 3) = %.15lf\n", root(3, 3.0));
  130.     printf("root(2, 9) = %.15lf\n", root(2, 9.0));
  131.     printf("root(4, 81) = %.15lf\n", root(4, 81.0));
  132.     // The only difference between the below method of 2^3.1 and the fpow() method is that
  133.     // fpow()'s job is to automate the transition from `2^3.1` to `2^3 * root(10, 2^1)`
  134.     // which is tricky because of the way floats work. (see 'GET_DEC(3.1) to 35 decimal places printout')
  135.     printf("2^3.1 = 2^3 * 2^0.1\n");
  136.     printf("8 * 2^(1/10) = 8 * root(10, 2)\n");
  137.     printf("root(10, 2) = %.15lf\n", root(10, 2.0));
  138.     printf("8 * root(10, 2) = %.15lf\n", 8 * root(10, 2.0));
  139. }
  140.  
  141. /* output:
  142.  * pow(2, 3) = 8.0
  143.  * pow(2, 3.1) = 8.574187700290345
  144.  * root(2, 2) = 1.414213562373095
  145.  * root(3, 3) = 1.442249570307408
  146.  * root(2, 9) = 3.000000000000000
  147.  * root(4, 81) = 3.000000000000000
  148.  * --
  149.  * numer(0.1) = 1
  150.  * denom(0.1) = 10
  151.  * GET_DEC(3.1) = 0.10000000000000008881784197001252323
  152.  * numer(GET_DEC(3.1)) = 1
  153.  * denom(GET_DEC(3.1)) = 10
  154.  * pow(2, 3.1) = 8.574187700290345
  155.  * root(2, 2) = 1.414213562373095
  156.  * root(3, 3) = 1.442249570307408
  157.  * root(2, 9) = 3.000000000000000
  158.  * root(4, 81) = 3.000000000000000
  159.  * 2^3.1 = 2^3 * 2^0.1
  160.  * 8 * 2^(1/10) = 8 * root(10, 2)
  161.  * root(10, 2) = 1.071773462536293
  162.  * 8 * root(10, 2) = 8.574187700290345
  163.  */
Add Comment
Please, Sign In to add comment