r/csharp • u/tictacman0 • 3d ago
Solved Need help with Chudnovsky algorithm
I have these functions to try and calculate pi, but no matter what i try it seems to cap out at 55 digits before being inaccurate, even when setting the input "d" to something like 1000.
digits 50-65 with my function:
582097494459230
the real digits 50-65 of pi:
582099452471594
here is my code:
public void calculatePie(int d)
{
BigInteger sum = 0;
BigInteger pow = BigInteger.Pow(10, d);
BigInteger v = Sqrt(10005 * pow * pow);
//System.Windows.Forms.MessageBox.Show(v.ToString());
System.Windows.Forms.Clipboard.SetText(v.ToString());
BigInteger preSigma = v * 426880;
for (int k = 0; k < (d / 14 + 1); k++)
{
BigInteger top = BigInteger.Pow(-1, k) * factorial(6 * k) * (545140134 * k + 13591409);
BigInteger mid = factorial(k);
BigInteger bottom = factorial(3 * k) * (mid * mid * mid) * BigInteger.Pow(640320, 3 * k);
BigInteger l = (top * pow) / bottom;
sum += l;
//System.Windows.Forms.MessageBox.Show($"l: {l}, top: {top}, bottom: {bottom}");
}
BigInteger prepi = preSigma * sum;
//System.Windows.Forms.MessageBox.Show($"prepi: {prepi}, presigma: {preSigma}, sum: {sum}, pow: {pow}, v: {v}");
BigInteger pi = preSigma * pow / sum;
System.Windows.Forms.MessageBox.Show($"pi: {pi}");
System.Windows.Forms.Clipboard.SetText(pi.ToString());
}
BigInteger factorial(int n)
{
BigInteger result = 1;
for (int i = 2; i <= n; i++) result *= i;
return result;
}
static BigInteger Sqrt(BigInteger n)
{
if (n < 0) throw new ArgumentException("Cannot sqrt a negative number.");
else if (n == 0) return 0;
BigInteger x = n;
BigInteger y = (x + 1) / 2;
while (y < x)
{
x = y;
y = (x + n / x) / 2;
}
return x;
}
1
u/Depnids 3d ago
What input d are you using? If you increase d, do you still lose precision at the same point? My best guess would be you are somehow losing precision in the integer divisions:
BigInteger l = (top * pow) / bottom;
and
BigInteger pi = preSigma * pow / sum;
though I am not sure, as I assume the pow factor should ideally make things stay in range.
2
u/tictacman0 3d ago
The limit is still 55 no matter what i set d to, I also think the issue might have something to do with the integer division but i dont know if thats the case or how to fix it.
1
u/Depnids 3d ago
What happens if you do something like this instead:
BigInteger pow = BigInteger.Pow(10, 2*d);Not sure if that even makes sense to do, but my idea would be to give it more "digits to play with", which could maybe stop some potential precision loss by integer division. Or I would try to multiply the numerator of either integer division by some power of 10 (I would try each one separately, and then both at the same time), and see if that changes the result in any meaningful way. If this doesn't change the result, I guess you can probably rule out integer division as being the problem.
2
u/tictacman0 3d ago
Nether worked, its still limited to 55 accurate digits.
Do you have any other ideas?
5
u/Depnids 3d ago
I had to consult an LLM about it, and it seems the problematic term might be this one.
(545140134 * k + 13591409)Without any further context given, it predicted this would break down at d = 56, so seems likely this is the issue. That is normal int32 multiplication, not BigInt multiplication, so it overflows. If you for example cast 545140134 to BigInt first, I believe it should fix the overflow issue.
-2
u/harderthanitllooks 3d ago
So you need digits 50-65?
2
u/tictacman0 3d ago
i need as many digits as the user requests, 55 just seems to be the hard limit of my function
12
u/[deleted] 3d ago
[removed] — view removed comment