10

I'm having a problem with C#. To be precise with the Math.pow(). If I try to calculate 15^14 then I get "29192926025390624". But if I calculate it with Wolfram Alpha I get "29192926025390625". As you can see this only difference is 1 number. Wolfram Alpha is correct though. Why isn't C# ? and how do I fix this so I can get the correct value in C# ?7

My code is fairly simple since I'm just trying with hardcoded examples. So what I'm doing is : Math.Pow(15,14); This gives 29192926025390624. And not "29192926025390625" which is the correct answer.

Links : Wolfram Alpha

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
Olivier_s_j
  • 5,490
  • 24
  • 80
  • 126
  • 5
    Without seeing your code, anything will be a guess. My guess is that Wolfram Alpha is calculating it using a higher precision floating point type. – ChrisF Nov 28 '10 at 15:23
  • 5
    By the way, assuming that 29192926025390625 is correct (it looks correct: it ends with a "5"), then `Math.Pow` behaves according to spec: 29192926025390624 **is** the nearest double-precision IEEE 754 number. The other nearby double-precision number is 29192926025390628. – Pascal Cuoq Nov 28 '10 at 15:39
  • It is computing correctly; it is your understand of floating-point arithmetic and the specification for `Math.Pow` that is flawed. Enjoy: http://docs.sun.com/source/806-3568/ncg_goldberg.html – jason Nov 28 '10 at 15:46

5 Answers5

11

Math.Pow operates on floating-point types, which are by definition inaccurate. If you need arbitrary precision integers, use an arbitrary precision integer type such as the BigInteger structure. BigInteger also has a Pow method.

Heinzi
  • 167,459
  • 57
  • 363
  • 519
  • The BigInteger.pow() did the trick (ModPow even). Thank you very much. – Olivier_s_j Nov 28 '10 at 16:09
  • 1
    @Ojtwist: Just a warning... if performance really matters for you, and that operation on BigInteger is repeated a really big number of times, you should think to change strategy (e.g. build your own Pow function for longs for example, as suggested in Yuriy Faktorovich's answer). – digEmAll Nov 28 '10 at 16:39
5

Math.Pow works on doubles. This implementation with long gets the correct answer:

Func<long, int, long> power = null;
power = (i, p) => p == 1 ? i : i*power(i, p - 1);
Console.WriteLine(power(15, 14));
Yuriy Faktorovich
  • 67,283
  • 14
  • 105
  • 142
  • 1
    be carefull with < 1 powers (looks like a stackoverflow to me :p) (handle the 0 case should be enought since with deal with ints) – Guillaume86 Dec 23 '10 at 15:34
4

Math.Pow works on doubles. Doubles are 64 bit floating point and have about 15-16 digits of precision in C#, and therefore, what you are seeing is a rounding error. That is how floating point numbers work.

If you need more precision, try to use decimal. It is 128 bits and uses 10 as the base. This gives you accurate representation of numbers up to 28-29 significant digits. You can easily define your own Pow method for decimal.

If decimal is not enough, turn to BigInteger, which was added in .NET 4.

driis
  • 161,458
  • 45
  • 265
  • 341
  • 1
    `decimal`'s are floating-point as well, they just use base 10 instead of 2 --> http://csharpindepth.com/Articles/General/Decimal.aspx – digEmAll Nov 28 '10 at 15:49
1

C#'s Math.pow returns a Double, an IEEE 754 standard floating point number. It only has 15 significant digits:

http://msdn.microsoft.com/en-us/library/system.math.pow.aspx

desertnaut
  • 57,590
  • 26
  • 140
  • 166
duffymo
  • 305,152
  • 44
  • 369
  • 561
1

Math.Pow() is working correctly its problem with double data type see this.

        double i = 29192926025390625;
        Console.WriteLine("{0}",i);//the result will be 29192926025390624.0

Oops Sorry, Check value by breakpoint; in your program;

Javed Akram
  • 15,024
  • 26
  • 81
  • 118