Daniel Neiva
Daniel Neiva

Reputation: 35

Getting wrong multiplication result in C

I'm working in a C code for calculating pi with the precision of 80 decimals, using Archimedes method. This video may elucidate about the method.

I'm basically calculating Pi by starting with a regular hexagon with diameter 2, and sides measuring 1 and doing Pi = Perimeter/Diameter, and doubling the number of sizes so I can get a polygon closer to a circle each time my program calculates it.

Here is the code:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main()
{
    long double pi, circunferencia, s, s1, a, b, diametro;
    int lado = 6;

    s=1;
    diametro = 2;

    while (lado<=(6*pow(2,27))){

        printf("numero de lados =%d\n", lado);

        a= sqrt(1-(s/2)*(s/2));
      //  printf("a= %.80Lf\n", a);
        b= 1 - a;
      //  printf("b= %.80Lf\n", b);
        s1= sqrt ((b*b)+((s/2)*(s/2)));
      //  printf("c= %.80Lf\n", s1);


        lado = lado*2;
        s = s1;
        circunferencia = lado * s1;
        pi = circunferencia/diametro;
        printf("\npi= %.80Lf\n\n\n", pi);

    }

    return 0;
}

With 227, I got up to about 15 decimals of precision, and lado = 805306368. If I do 228 or higher, the multiplication goes wrong from this part and I start to get negative numbers. Everything gets messed up and lado, suddenly is set to 0 and it turns into a infinite loop.

I'm a beginner in C and programming in general, if you guys could recommend me some reading on the subject, in order to understand how exactly this works and why am I getting this bug, it would be awesome.

I'm using Code::Blocks version 17.12, GNU GCC Compiler (I have "Have gcc follow the 2011 ISO C language standard [-std=c11]" option enabled, because I couldn't use "%Lf" to refer to a long double variable) and a Windows 10 x64 Operational System.

Upvotes: 2

Views: 1073

Answers (1)

chux
chux

Reputation: 153468

If i do 2^28 or higher, the multiplication goes wrong from this part,

lado<=(6*pow(2,27)) is OK, yet lado = lado*2; begins to overflow int math about then.

Once lado > INT_MAX/2 (likely 1,073,741,823), int overflow occurs with lado*2 and anything may happen. In OP's case, lado eventually become 0.

Code could use long long

// int lado = 6;
long long lado = 6;
...
  // printf("numero de lados =%d\n", lado);
  printf("numero de lados =%lld\n", lado);

That will patch the immediate loop concern for about another 20 or so loops.


I have my doubts that code will achieve "calculating pi with the precision of 80 decimals" with long double (maybe 17 - 34 decimal digits precision).


OP reported "my teacher said i could storage up to 80 digits with long double" certainty meant a long double of 80 bits x86 extended precision format or about 20 decimal digits of precision.

I suggest using long double functions instead of double ones.

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main() {
  long double pi, circunferencia, s, s1, a, b, diametro;
  long long lado = 6;

  s = 1;
  diametro = 2;

  while (lado <= (6 * pow(2, 27))) {
    printf("numero de lados =%lld\t", lado);

    // a = sqrt(1 - (s / 2) * (s / 2));
    a = sqrtl(1 - (s / 2) * (s / 2));
    b = 1 - a;
    // s1 = sqrt((b * b) + ((s / 2) * (s / 2)));
    s1 = hypotl(b, s / 2);

    lado = lado * 2;
    s = s1;
    circunferencia = lado * s1;
    pi = circunferencia / diametro;
    printf("pi= %.40Lf\n", pi);
  }
  printf("best                      \tpi= %.40Lf\n", acosl(-1.0));
  return 0;
}

Sample Output

numero de lados =6  pi= 3.1058285412302491482368360653509853364085
numero de lados =12 pi= 3.1326286132812381970275117382129792531487
numero de lados =24 pi= 3.1393502030468672071242958176995330177306
....
numero de lados =201326592  pi= 3.1415926535897932057699033503439522974077
numero de lados =402653184  pi= 3.1415926535897932296223511450250498455716
numero de lados =805306368  pi= 3.1415926535897932356938833109438746760134
best                        pi= 3.1415926535897932385128089594061862044327
// in my case good to about     1 23456789012345678 (18 digits)

Upvotes: 4

Related Questions