1

This situation really confused me: I have one .NET application doing some floating number calculation. It seems having problem to do the division, Math.Pow, and Math.Exp. For example:

double _E1 = 20616579.5;
double sub = 19000;
double total = 19623;
double percent = sub / total;                 //0.96825152635574341
double _result1 = Math.Pow(_E1, percent);     //12078177.0
double _result2 = Math.Exp(percent * Math.Log(_E1)); //12078184.730266357   

all three results, percent, _result1, and _result2 are incorrect (you can use calculator to verify).

I have another .NET program running the same code, on the same machine, gives the correct results:

  • _result1 = 12078180.370260473
  • _result2 = 12078180.370260468
  • percent = 0.96825154155837534

By just looking at the result for percent, the precision only goes to 7 decimal digits. The Double usually goes to 16 decimal digits.

I have another even simpler example as follows: enter image description hereenter image description here

_outcome equals to some ridiculous number. but it shows correct result when I put cursor on top of "*".

Please help, drove me crazy in the last few days.

UPDATE: the problem solved. DirectX was the culprit. see: Can floating-point precision be thread-dependent?

Community
  • 1
  • 1
  • possible duplicate of [Why can't decimal numbers be represented exactly in binary?](http://stackoverflow.com/questions/1089018/why-cant-decimal-numbers-be-represented-exactly-in-binary) – Matt Burland Feb 13 '14 at 15:07
  • What version of .NET? I get the exact same result (`12078180.3702605` for `_result1` and `_result2` in LinqPad, which targets .NET 4.x. – D Stanley Feb 13 '14 at 15:12
  • 1
    @MattBurland I don't think it's the same question - `double` has plenty of precision and the two expressions should result in the same answer. – D Stanley Feb 13 '14 at 15:34
  • @Stanley I used both .net 3.5 and 4.0. make no difference for me. – user3306496 Feb 13 '14 at 15:37
  • 1
    Since the answer does not reproduce, for other people or for you on another machine, you should reduce it to a [short, self-contained compilable example](http://sscce.org). The process of doing so will likely reveal the problem. – Eric Postpischil Feb 13 '14 at 16:29
  • 1
    Note that the value you show for `percent` is almost *exactly* the value you'd expect to see if `percent` were declared as `float` rather than `double`. – Mark Dickinson Feb 13 '14 at 18:09
  • @MarkDickinson: It is in fact exactly that value; the neighboring `double` values display differently when show with the same number of digits. – Eric Postpischil Feb 13 '14 at 18:53

2 Answers2

1

Your exact code doesn't compile (you have percent declared twice). I suspect that there's a conversion somewhere else that you haven't posted (perhaps a conversion to float somewhere that will reduce precision to 6-7 digits).

When I run your code (minus the extra declaration of percent) in LinqPad I get the correct result:

void Main()
{
    double _E1 = 20616579.5;
    double sub = 19000;
    double total = 19623;
    double percent = sub / total;                 
    double _result1 = Math.Pow(_E1, percent);     
    double _result2 = Math.Exp(percent * Math.Log(_E1));  

    percent.Dump();     // 0.968251541558375
    _result1.Dump();    // 12078180.3702605
    _result2.Dump();    // 12078180.3702605
}
D Stanley
  • 149,601
  • 11
  • 178
  • 240
  • 1
    Why are people voting this down? Perhaps because they think it is more suitable as a comment as it does not answer the question? But it may in fact hold the answer: The error is clearly too large to be ordinary floating-point rounding issues, so it is likely a bug, quite possibly of the nature this answer suggests. – Eric Postpischil Feb 13 '14 at 16:27
  • Thanks to observations by Mark Dickinson and D Stanley, the following suffice to reproduce the errant behavior: Convert `percent` to `float`. Convert `_result1` to `float`. Convert `Math.log(_E1)` to `float` and use `float` arithmetic to multiply it by `percent` (in the expression where `_result2` is calculated). – Eric Postpischil Feb 13 '14 at 19:13
0

Double only has the precision of 15-16 digits. I think this is where you get your error.

Try using Decimal (http://msdn.microsoft.com/en-us/library/364x0z75.aspx) instead. Can handle 28-29 digits.

ohlmar
  • 958
  • 8
  • 17
  • 2
    `Math.Pow` and `Math.Exp` only accept `double` arguments, so you'd have to convert to `double` anyways. Besides, the inconsistencies show up on the 7th digit, so `double` should have plenty of precision. – D Stanley Feb 13 '14 at 15:22
  • 1
    double should not be the problem. I have another .net program running side-by-side on the same machine. The same code give different results! – user3306496 Feb 13 '14 at 15:39