.NET C# Double equivalent System.Numerics.BigInteger - c#

I'm am currently writing a program that calculates the digits of pi, and I have a problem. After three iterations the number of correct digits exceeds the memory available in a double.
I heard of the System.Numerics.BigInteger type (in System.Numerics.dll), but I need to use floating point numbers. I do not understand the algorithm well enough to use integers.
It would be great if a version of the BigInteger exists which supports a decimal point.
Below I have put my C# code:
var a = 1.0;
var b = 1 / Math.Sqrt(2);
var t = 0.25;
var p = 1.0;
double anext, bnext, tnext, pnext;
int count = 0;
for (int i = 1; i <= accuracy; i++ )
{
anext = (a + b) / 2;
bnext = Math.Sqrt(a * b);
tnext = (t - p * ((a - anext) * (a - anext)));
pnext = 2 * p;
a = anext;
b = bnext;
t = tnext;
p = pnext;
var pi = ((a + b) * (a + b)) / (4 * t);
Console.WriteLine("Iteration = " + i.ToString());
Console.WriteLine("Pi = " + pi + "\n\n\n\n");
}

The BigInteger class was written by Melitta Andersen of the BCL team, her first project. It was actually shipped in .NET 3.5 but was hidden, the class was marked internal. Not to become public until .NET 4.0. She also wrote a floating point version, called BigRational. Similar problem, didn't make it into .NET 4.0. These are strange and unexplainable decisions whose reasoning I'm not privy to.
Nevertheless, the source code for BigRational is available. You can download it here.

If you're trying to calculate Pi to an arbitrary number of digits of precision, then none of the numeric types available will be valid. You're going to have to use a string (or, preferably, a StringBuilder) and compute the number digit-by-digit.

Related

Getting Different Values for the same formula in C++ Than in C#

I have a formula from a C++ application that I have implemented in C# but I am producing vastly different results.
The Sample Latitude is:
Here is the C++ Implementation:
double lat = 0.959931088596881 //In Radians
double lon = -3.14159265358979 //In Radians
double alt = altitude;
double a = 6378137;
double e = 8.1819190842622e-2;
double N = a / sqrt(1.0 - (e * e) * (sin(lat) * sin(lat)));
x = (N+alt) * cos(lat) * cos(lon);
Final result for X: -3.66659e+006
Here is the C# Implementation:
double lat = this.DegreesToRadians(latitude);
double lon = this.DegreesToRadians(longitude);
double alt = altitude;
double a = 6378137;
double e = 8.1819190842622e-2;
double N = a / Math.Sqrt(1.0 - (e * e) * (Math.Sin(lat) * Math.Sin(lat)));
x = (N + alt) * Math.Cos(lat) * Math.Cos(lon);
Final result for X: -3666593.52237417
I am sure there must be something simple I am missing. I have tried pulling out different pieces and parts but can't quite figure out where the difference is occurring.
I have a formula from a C++ application that I have implemented in C# but I am producing vastly different results.
Nope, you're getting very, very similar results - with different representations.
C++: -3.66659e+006
C#: -3666593.52237417
Those are the same number (to 6 significant digits) - the C++ representation is just using scientific representation.
Here's a piece of C# to demonstrate the same value shown in two ways:
using System;
class Test
{
static void Main(string[] args)
{
// Source code using scientific representation
double value = -3.66659e+006;
Console.WriteLine(value.ToString("G")); // General representation
Console.WriteLine(value.ToString("E")); // Scientific representation
}
}
Output:
-3666590
-3.666590E+006
Now we can't tell what the C++ result is beyond the first 6 significant digits, based just on your output, although you can probably use printf to show you more details. But the values are at least very similar.

BesselK Function in C#

I am attempting to implement the BesselK method from Boost (a C++ library).
The Boost method accepts two doubles and returns a double. (I have it implemented below as cyl_bessel_k .)
The equation I modeled this off of comes from Boosts documention:
http://www.boost.org/doc/libs/1_45_0/libs/math/doc/sf_and_dist/html/math_toolkit/special/bessel/mbessel.html
I have also been checking values against Wolfram:
http://www.wolframalpha.com/input/?i=BesselK%283%2C1%29
I am able to match output from the Boost method when passing a positive non-integer value for "v". However, when an integer is passed, my output is severely off. So,there is an obvious discontinuity issue. From reading up on this, it seems that this issue arises from passing a negative integer to the gamma function. Somehow reflection comes into play here with the Bessel_I method, but I'm nearing the end of my math skillset.
1.) What needs to happen to the bessel_i method with reflection to make this work?
2.) I'm currently doing a partial sum approach. Boost uses a continuous fraction approach. How can I modify this to account for convergence?
Any input is appreciated! Thank you!
static double cyl_bessel_k(double v, double x)
{
if (v > 0)
{
double iNegativeV = cyl_bessel_i(-v, x);
double iPositiveV = cyl_bessel_i(v, x);
double besselSecondKind = (Math.PI / 2) * ((iNegativeV - iPositiveV ) / (Math.Sin(Math.PI * v)));
return besselSecondKind;
}
else
{
//error handling
}
}
static double cyl_bessel_i(double v, double x)
{
if (x == 0)
{
return 0;
}
double summed = 0;
double a = Math.Pow((0.5d * x), v);
for (double k = 0; k < 10; k++) //how to account for convergence? 10 is arbitrary
{
double b = Math.Pow(0.25d * Math.Pow(x, 2), k);
double kFactorial = SpecialFunctions.Factorial((int)k); //comes from MathNet.Numerics (Nuget)
double gamma = SpecialFunctions.Gamma(v + k + 1); //comes from MathNet.Numerics
summed += b / (kFactorial * gamma);
}
return a * summed;
}
After lots of refactoring and trying things that didn't work, this is what I came up with. It's mostly Boost logic that has been adapted and translated into C#.
It's not perfect though (likely due to rounding, precision,etc). Any improvements are welcome! Max error is 0.0000001926% between true Bessel_K value from Wolfram and my adapted method. This is occurs when parameter 'v' is an integer. For my purposes, this was close enough.
Link to fiddle:
https://dotnetfiddle.net/QIYzK6
Hopefully it saves someone some headache.

Why is (double)0.6f > (double)(6/10f)?

This is what happens on my computer:
(double)(float)0.6
= 0.60000002384185791
(double)0.6f
= 0.60000002384185791
(double)(6/10f)
= 0.6
(double)(float)(6/10f)
= 0.6
6/10f is also a float,how come it can be precisely 0.6?
In my mind (double)(6/10f) should also be 0.60000002384185791.
Can someone help explain this? thanks!
First, its important to bear in mind that 0.6 cannot be accurately represented as a float however it can be accurately represented as a double (the inaccuracies of floating point arithmetic are well documented, if its not clear why 0.6 cannot be accurately represented as a float, try this link)
The reason why you are seeing the above behaviour is down to the compiler - if you take a look at the compiled assembly in reflector then whats going on here is a little clearer:
(UPDATE I've changed the code so that it doesn't use Console.WriteLine, as I realised that the compiler was choosing an overload for you, which confused the situation)
// As written in source
var j = (double)(float)0.6;
var k = (double)0.6f;
var l = (double)(6/10f);
var m = (double)(float)(6/10f);
// Code as seen by Reflector
double j = 0.60000002384185791;
double k = 0.60000002384185791;
double l = 0.6;
double m = 0.6;
Why the compiler chooses to compile in this particular way is beyond me (fyi, this is all with optimisations turned off)
Some interesting other cases:
// Code
var a = 0.6;
var b = (double)0.6;
var c = 0.6f;
var d = (float)0.6;
var e = 6 / 10;
var f = 6 / (10f);
var g = (float)(6 / 10);
var h = 6 / 10f;
var i = (double)6 / 10;
// Prints out 0.60000002384185791
double n = (float)0.6;
double o = f;
// As seen by Reflector
double a = 0.6;
double b = 0.6;
float c = 0.6f;
float d = 0.6f;
int e = 0;
float f = 0.6f;
float g = 0f;
float h = 0.6f;
double i = 0.6;
double n = 0.60000002384185791;
double o = f;
The compiler only seems to do the above trick in a couple of special cases, why it does this only when casting to a double is completely beyond me!
The rest of the time it seems to do some trickery to make floating point arithmetic seem to work where in fact it normally wouldn't.
It appears to be rounding the result. Are you displaying the result with the necessary digits of precision? You can use this c# class from Jon Skeet to get the exact numeric representation of the result printed out.
Note that ToString() will not always print all of the digits, nor will the Visual Studio debugger.
If I were a betting man, I'd say the difference is in where the coercion is happening. In the latter two examples (the ones with 6/10f), there are two literals that are both whole numbers (the integer 6 and the float 10.00000000...). The division appears to be happening after the coercion, at least in the compiler you're using. In the first two examples, you have a fractional float literal (0.6) which cannot be adequately expressed as a binary value within the mantissa of a float. Coercing that value to a double cannot repair the damage that was already done.
In the environments that are producing completely consistent results, the division is occurring before the coercion to double (the 6 will be coerced to a float for the division to match the 10, the division is carried out in float space, then the result is coerced to a double).

Trying to calculate Pi to N number of decimals with C#

Note: I've already read this topic, but I don't understand it and it doesn't provide a solution I could use. I'm terrible with number problems.
What's a simple way to generate Pi to what number of decimals a user wants? This isn't for homework, just trying to complete some of the projects listed here:
Link
A classic algorithm for calculating digits of pi is the Gauss-Legendre algorithm. While it is not as fast as some of the more modern algorithms it does have the advantage of being understandable.
Let
a_0 = 1
b_0 = 1/Sqrt(2)
t_0 = 1/4
p_0 = 1
Then
a_(n+1) = (a_n + b_n) / 2
b_(n+1) = Sqrt(a_n * b_n)
t_(n+1) = t_n - p_n * (a_n - a_(n+1))^2
p_(n+1) = 2 * p_n
Then
pi =. (a_n + b_n)^2 / (4 * t_n)
Here (=. means "approximately equal to") This algorithm exhibits quadratic convergence (the number of correct decimal places doubles with each iteration).
I'll leave it to you to translate this to C# including discovering an arbitrary-precision arithmetic library.
The topic your talking about calculate the value of PI using the taylor series. Using the function "double F (int i)" wrote on that topic will give you the value of PI after "i" terms.
This way of calculating PI is kind of slow, i suggest you to look at the PI fast algorithm.
You can also find one implementation here that get the calculate PI to the n th digit.
Good luck!
If you take a close look into this really good guide:
Patterns for Parallel Programming: Understanding and Applying Parallel Patterns with the .NET Framework 4
You'll find at Page 70 this cute implementation (with minor changes from my side):
static decimal ParallelPartitionerPi(int steps)
{
decimal sum = 0.0;
decimal step = 1.0 / (decimal)steps;
object obj = new object();
Parallel.ForEach(Partitioner.Create(0, steps),
() => 0.0,
(range, state, partial) =>
{
for (int i = range.Item1; i < range.Item2; i++)
{
decimal x = (i + 0.5) * step;
partial += 4.0 / (1.0 + x * x);
}
return partial;
},
partial => { lock (obj) sum += partial; });
return step * sum;
}

How do I calculate PI in C#?

How can I calculate the value of PI using C#?
I was thinking it would be through a recursive function, if so, what would it look like and are there any math equations to back it up?
I'm not too fussy about performance, mainly how to go about it from a learning point of view.
If you want recursion:
PI = 2 * (1 + 1/3 * (1 + 2/5 * (1 + 3/7 * (...))))
This would become, after some rewriting:
PI = 2 * F(1);
with F(i):
double F (int i) {
return 1 + i / (2.0 * i + 1) * F(i + 1);
}
Isaac Newton (you may have heard of him before ;) ) came up with this trick.
Note that I left out the end condition, to keep it simple. In real life, you kind of need one.
How about using:
double pi = Math.PI;
If you want better precision than that, you will need to use an algorithmic system and the Decimal type.
If you take a close look into this really good guide:
Patterns for Parallel Programming: Understanding and Applying Parallel Patterns with the .NET Framework 4
You'll find at Page 70 this cute implementation (with minor changes from my side):
static decimal ParallelPartitionerPi(int steps)
{
decimal sum = 0.0;
decimal step = 1.0 / (decimal)steps;
object obj = new object();
Parallel.ForEach(
Partitioner.Create(0, steps),
() => 0.0,
(range, state, partial) =>
{
for (int i = range.Item1; i < range.Item2; i++)
{
decimal x = (i - 0.5) * step;
partial += 4.0 / (1.0 + x * x);
}
return partial;
},
partial => { lock (obj) sum += partial; });
return step * sum;
}
There are a couple of really, really old tricks I'm surprised to not see here.
atan(1) == PI/4, so an old chestnut when a trustworthy arc-tangent function is
present is 4*atan(1).
A very cute, fixed-ratio estimate that makes the old Western 22/7 look like dirt
is 355/113, which is good to several decimal places (at least three or four, I think).
In some cases, this is even good enough for integer arithmetic: multiply by 355 then divide by 113.
355/113 is also easy to commit to memory (for some people anyway): count one, one, three, three, five, five and remember that you're naming the digits in the denominator and numerator (if you forget which triplet goes on top, a microsecond's thought is usually going to straighten it out).
Note that 22/7 gives you: 3.14285714, which is wrong at the thousandths.
355/113 gives you 3.14159292 which isn't wrong until the ten-millionths.
Acc. to /usr/include/math.h on my box, M_PI is #define'd as:
3.14159265358979323846
which is probably good out as far as it goes.
The lesson you get from estimating PI is that there are lots of ways of doing it,
none will ever be perfect, and you have to sort them out by intended use.
355/113 is an old Chinese estimate, and I believe it pre-dates 22/7 by many years. It was taught me by a physics professor when I was an undergrad.
Good overview of different algorithms:
Computing pi;
Gauss-Legendre-Salamin.
I'm not sure about the complexity claimed for the Gauss-Legendre-Salamin algorithm in the first link (I'd say O(N log^2(N) log(log(N)))).
I do encourage you to try it, though, the convergence is really fast.
Also, I'm not really sure about why trying to convert a quite simple procedural algorithm into a recursive one?
Note that if you are interested in performance, then working at a bounded precision (typically, requiring a 'double', 'float',... output) does not really make sense, as the obvious answer in such a case is just to hardcode the value.
What is PI? The circumference of a circle divided by its diameter.
In computer graphics you can plot/draw a circle with its centre at 0,0 from a initial point x,y, the next point x',y' can be found using a simple formula:
x' = x + y / h : y' = y - x' / h
h is usually a power of 2 so that the divide can be done easily with a shift (or subtracting from the exponent on a double). h also wants to be the radius r of your circle. An easy start point would be x = r, y = 0, and then to count c the number of steps until x <= 0 to plot a quater of a circle. PI is 4 * c / r or PI is 4 * c / h
Recursion to any great depth, is usually impractical for a commercial program, but tail recursion allows an algorithm to be expressed recursively, while implemented as a loop. Recursive search algorithms can sometimes be implemented using a queue rather than the process's stack, the search has to backtrack from a deadend and take another path - these backtrack points can be put in a queue, and multiple processes can un-queue the points and try other paths.
Calculate like this:
x = 1 - 1/3 + 1/5 - 1/7 + 1/9 (... etc as far as possible.)
PI = x * 4
You have got Pi !!!
This is the simplest method I know of.
The value of PI slowly converges to the actual value of Pi (3.141592165......). If you iterate more times, the better.
Here's a nice approach (from the main Wikipedia entry on pi); it converges much faster than the simple formula discussed above, and is quite amenable to a recursive solution if your intent is to pursue recursion as a learning exercise. (Assuming that you're after the learning experience, I'm not giving any actual code.)
The underlying formula is the same as above, but this approach averages the partial sums to accelerate the convergence.
Define a two parameter function, pie(h, w), such that:
pie(0,1) = 4/1
pie(0,2) = 4/1 - 4/3
pie(0,3) = 4/1 - 4/3 + 4/5
pie(0,4) = 4/1 - 4/3 + 4/5 - 4/7
... and so on
So your first opportunity to explore recursion is to code that "horizontal" computation as the "width" parameter increases (for "height" of zero).
Then add the second dimension with this formula:
pie(h, w) = (pie(h-1,w) + pie(h-1,w+1)) / 2
which is used, of course, only for values of h greater than zero.
The nice thing about this algorithm is that you can easily mock it up with a spreadsheet to check your code as you explore the results produced by progressively larger parameters. By the time you compute pie(10,10), you'll have an approximate value for pi that's good enough for most engineering purposes.
Enumerable.Range(0, 100000000).Aggregate(0d, (tot, next) => tot += Math.Pow(-1d, next)/(2*next + 1)*4)
using System;
namespace Strings
{
class Program
{
static void Main(string[] args)
{
/* decimal pie = 1;
decimal e = -1;
*/
var stopwatch = new System.Diagnostics.Stopwatch();
stopwatch.Start(); //added this nice stopwatch start routine
//leibniz formula in C# - code written completely by Todd Mandell 2014
/*
for (decimal f = (e += 2); f < 1000001; f++)
{
e += 2;
pie -= 1 / e;
e += 2;
pie += 1 / e;
Console.WriteLine(pie * 4);
}
decimal finalDisplayString = (pie * 4);
Console.WriteLine("pie = {0}", finalDisplayString);
Console.WriteLine("Accuracy resulting from approximately {0} steps", e/4);
*/
// Nilakantha formula - code written completely by Todd Mandell 2014
// π = 3 + 4/(2*3*4) - 4/(4*5*6) + 4/(6*7*8) - 4/(8*9*10) + 4/(10*11*12) - (4/(12*13*14) etc
decimal pie = 0;
decimal a = 2;
decimal b = 3;
decimal c = 4;
decimal e = 1;
for (decimal f = (e += 1); f < 100000; f++)
// Increase f where "f < 100000" to increase number of steps
{
pie += 4 / (a * b * c);
a += 2;
b += 2;
c += 2;
pie -= 4 / (a * b * c);
a += 2;
b += 2;
c += 2;
e += 1;
}
decimal finalDisplayString = (pie + 3);
Console.WriteLine("pie = {0}", finalDisplayString);
Console.WriteLine("Accuracy resulting from {0} steps", e);
stopwatch.Stop();
TimeSpan ts = stopwatch.Elapsed;
Console.WriteLine("Calc Time {0}", ts);
Console.ReadLine();
}
}
}
public static string PiNumberFinder(int digitNumber)
{
string piNumber = "3,";
int dividedBy = 11080585;
int divisor = 78256779;
int result;
for (int i = 0; i < digitNumber; i++)
{
if (dividedBy < divisor)
dividedBy *= 10;
result = dividedBy / divisor;
string resultString = result.ToString();
piNumber += resultString;
dividedBy = dividedBy - divisor * result;
}
return piNumber;
}
In any production scenario, I would compel you to look up the value, to the desired number of decimal points, and store it as a 'const' somewhere your classes can get to it.
(unless you're writing scientific 'Pi' specific software...)
Regarding...
... how to go about it from a learning point of view.
Are you trying to learning to program scientific methods? or to produce production software? I hope the community sees this as a valid question and not a nitpick.
In either case, I think writing your own Pi is a solved problem. Dmitry showed the 'Math.PI' constant already. Attack another problem in the same space! Go for generic Newton approximations or something slick.
#Thomas Kammeyer:
Note that Atan(1.0) is quite often hardcoded, so 4*Atan(1.0) is not really an 'algorithm' if you're calling a library Atan function (an quite a few already suggested indeed proceed by replacing Atan(x) by a series (or infinite product) for it, then evaluating it at x=1.
Also, there are very few cases where you'd need pi at more precision than a few tens of bits (which can be easily hardcoded!). I've worked on applications in mathematics where, to compute some (quite complicated) mathematical objects (which were polynomial with integer coefficients), I had to do arithmetic on real and complex numbers (including computing pi) with a precision of up to a few million bits... but this is not very frequent 'in real life' :)
You can look up the following example code.
I like this paper, which explains how to calculate π based on a Taylor series expansion for Arctangent.
The paper starts with the simple assumption that
Atan(1) = π/4 radians
Atan(x) can be iteratively estimated with the Taylor series
atan(x) = x - x^3/3 + x^5/5 - x^7/7 + x^9/9...
The paper points out why this is not particularly efficient and goes on to make a number of logical refinements in the technique. They also provide a sample program that computes π to a few thousand digits, complete with source code, including the infinite-precision math routines required.
The following link shows how to calculate the pi constant based on its definition as an integral, that can be written as a limit of a summation, it's very interesting:
https://sites.google.com/site/rcorcs/posts/calculatingthepiconstant
The file "Pi as an integral" explains this method used in this post.
First, note that C# can use the Math.PI field of the .NET framework:
https://msdn.microsoft.com/en-us/library/system.math.pi(v=vs.110).aspx
The nice feature here is that it's a full-precision double that you can either use, or compare with computed results. The tabs at that URL have similar constants for C++, F# and Visual Basic.
To calculate more places, you can write your own extended-precision code. One that is quick to code and reasonably fast and easy to program is:
Pi = 4 * [4 * arctan (1/5) - arctan (1/239)]
This formula and many others, including some that converge at amazingly fast rates, such as 50 digits per term, are at Wolfram:
Wolfram Pi Formulas
PI (π) can be calculated by using infinite series. Here are two examples:
Gregory-Leibniz Series:
π/4 = 1 - 1/3 + 1/5 - 1/7 + 1/9 - ...
C# method :
public static decimal GregoryLeibnizGetPI(int n)
{
decimal sum = 0;
decimal temp = 0;
for (int i = 0; i < n; i++)
{
temp = 4m / (1 + 2 * i);
sum += i % 2 == 0 ? temp : -temp;
}
return sum;
}
Nilakantha Series:
π = 3 + 4 / (2x3x4) - 4 / (4x5x6) + 4 / (6x7x8) - 4 / (8x9x10) + ...
C# method:
public static decimal NilakanthaGetPI(int n)
{
decimal sum = 0;
decimal temp = 0;
decimal a = 2, b = 3, c = 4;
for (int i = 0; i < n; i++)
{
temp = 4 / (a * b * c);
sum += i % 2 == 0 ? temp : -temp;
a += 2; b += 2; c += 2;
}
return 3 + sum;
}
The input parameter n for both functions represents the number of iteration.
The Nilakantha Series in comparison with Gregory-Leibniz Series converges more quickly. The methods can be tested with the following code:
static void Main(string[] args)
{
const decimal pi = 3.1415926535897932384626433832m;
Console.WriteLine($"PI = {pi}");
//Nilakantha Series
int iterationsN = 100;
decimal nilakanthaPI = NilakanthaGetPI(iterationsN);
decimal CalcErrorNilakantha = pi - nilakanthaPI;
Console.WriteLine($"\nNilakantha Series -> PI = {nilakanthaPI}");
Console.WriteLine($"Calculation error = {CalcErrorNilakantha}");
int numDecNilakantha = pi.ToString().Zip(nilakanthaPI.ToString(), (x, y) => x == y).TakeWhile(x => x).Count() - 2;
Console.WriteLine($"Number of correct decimals = {numDecNilakantha}");
Console.WriteLine($"Number of iterations = {iterationsN}");
//Gregory-Leibniz Series
int iterationsGL = 1000000;
decimal GregoryLeibnizPI = GregoryLeibnizGetPI(iterationsGL);
decimal CalcErrorGregoryLeibniz = pi - GregoryLeibnizPI;
Console.WriteLine($"\nGregory-Leibniz Series -> PI = {GregoryLeibnizPI}");
Console.WriteLine($"Calculation error = {CalcErrorGregoryLeibniz}");
int numDecGregoryLeibniz = pi.ToString().Zip(GregoryLeibnizPI.ToString(), (x, y) => x == y).TakeWhile(x => x).Count() - 2;
Console.WriteLine($"Number of correct decimals = {numDecGregoryLeibniz}");
Console.WriteLine($"Number of iterations = {iterationsGL}");
Console.ReadKey();
}
The following output shows that Nilakantha Series returns six correct decimals of PI with one hundred iterations whereas Gregory-Leibniz Series returns five correct decimals of PI with one million iterations:
My code can be tested >> here
Here is a nice way:
Calculate a series of 1/x^2 for x from 1 to what ever you want- the bigger number- the better pie result. Multiply the result by 6 and to sqrt().
Here is the code in c# (main only):
static void Main(string[] args)
{
double counter = 0;
for (double i = 1; i < 1000000; i++)
{
counter = counter + (1 / (Math.Pow(i, 2)));
}
counter = counter * 6;
counter = Math.Sqrt(counter);
Console.WriteLine(counter);
}
public double PI = 22.0 / 7.0;

Categories