I am trying to self teach myself C (C99 I think? gcc 8.1.0) coming from python/java. One of the practice problems I am working on is how to calculate pi to a given decimal.
I am currently using the following equation 2 * (Arcsin(sqrt(1 - 0.5^2)) + abs(Arcsin(0.5))).
float pi_find(float nth)
{
float x, y, z;
/* Equation = 2 * (Arcsin(sqrt(1 - x^2)) + abs(Arcsin(x))) [x|-1<=x=>1, xeR]*/
x = sqrt(1-pow(nth, 2)); /* Carrot (^) notation does not work, use pow() */
y = fabs(asin(nth)); /* abs is apparently int only, use fabs for floats */
z = x+y;
printf("x: %f\ny: %f\nsum: %f\n", x, y, (x+y));
printf("%f\n", asin(z));
return 2 * asin(z); /* <- Error Happens */
}
int main()
{
float nth = 0.5f;
double pi = pi_find(nth);
printf("Pi: %f\n", pi);
return 0;
}
Results:
x: 0.866025
y:0.523599
sum: 1.389624
z:-1.#IND00
Pi:-1.#IND00
I know the issue lies in the addition of x + y
which sums out to 1.389... and asin()
can only handle values between -1 and +1 inclusive.
HOWEVER!
I am using Wolfram Alpha along side python to check the calc is correct at every step and it can calculate asin(1.389...)
. [1]
I don't understand Imaginary mathematics, it is far beyond my capabilities as a mathematician but below is what Wolfram is doing. [2]
1.570796 -0.8563436 i
Interpreting as: 0.8563436 i
Assuming multiplication | Use a list instead
Assuming i is the imaginary unit | Use i as a variable instead
While writing this I found out about the _Imaginary
Datatype added in C99, but I don't really understand if it's doing the same thing as what Wolfram does.
Also looked up how imaginary numbers worked, but I don't really understand how 'The square roots of a negative number cannot be distinguished until one of the two is defined as the imaginary unit' works. [3]
Can someone nudge me in the direction to fix this please? It is obviously a knowledge issue and not a mathematical or language limitation
p.s yes I know it's trash code, I am using a weird way of debugging before I rewrite it properly.
[1]:Wolfram_Alpha Calculation [2]:Wolfram_Alpha Assumption [3]:Imaginary Numbers
The problem is you're grouping the expression incorrectly. The desired expression is:
2 * (Arcsin(sqrt(1 - 0.5^2)) + abs(Arcsin(0.5)))
With nth substituted for 0.5, this becomes:
2 * (Arcsin(sqrt(1 - nth^2)) + abs(Arcsin(nth))).
In particular, the argument to the first Arcsin is sqrt(1 - nth^2)), and the argument to the second Arcsin is nth.
You're also better off using nth * nth
rather than pow(nth, 2)
. It's both faster and more accurate.
So what you want is:
x = asin(sqrt(1 - nth*nth));
y = fabs(asin(nth));
r = 2*(x + y);
Notice that the argument to asin
can never have magnitude greater than 1 (as long as nth is less than 1).
Also, as I mentioned earlier in a comment, you should change all your float
variables to double
. You're using the double-precision math library functions anyway, so there's no reason to discard half of the precision by storing the results in float
variables.