cwindowsmathwolframalpha

Issue with asin() while calculating pi


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


Solution

  • 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.