-2

Please notice that I am not asking why a double value changes into another precision, but how can I make the results to be the same.

I appreciate all the comments and answers below, but I didn't get a solution to my problem.

My question again.

I just met a problem when rewriting the code from C++ to C# of the precision problem in double value,

I have a method to calculate the result of a financial product of several double values, but when I compare the results, I got different but similar results from C++ and C# program due to the precision of the double value.

I debug the program in C++ I found that after I set the values to a and b double a = 4.9; double b = 5.1;

The value of a and b changes to, a is 4.9000000000000004 and b is 5.0999999999999996. But in C#, a is still 4.9 and b is still 5.1, and finally, I got the results of -0.062579630921710816(C++ result), and -0.062579644244387111(C# result)

I am totally new in C# and C++, so are there any solutions to make the calculation result to be the same, please (I cannot change the C++ code)? Or is it possible to make the calculation result to be the same?

Rei Ryu
  • 1
  • 5
  • formula and values? or if it's possible, try to change variables as float. – Arphile Feb 13 '20 at 02:06
  • 1
    @Arphile Why `float`? – ProgrammingLlama Feb 13 '20 at 02:07
  • Is double suitable for financial product? – Louis Go Feb 13 '20 at 02:08
  • 1
    No, in C# it is not 4.9 or 5.1, guaranteed. It's just that C#'s debugger automatically rounds it off for you. You'll be surprised to learn that neither 4.9, nor 5.1, can be accurately expressed in traditional floating pointer representation [because floating point math is broken](https://stackoverflow.com/questions/588004/is-floating-point-math-broken). – Sam Varshavchik Feb 13 '20 at 02:09
  • 4
    Does this answer your question? [Is floating point math broken?](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) – Mox Feb 13 '20 at 02:11
  • But why the results are not the same? – Rei Ryu Feb 13 '20 at 02:29
  • I believe .NET recognises the recurring endings (i.e. `00000000000000X` and `099999999999999X`) and simply discards them in the basic `.ToString()` method, although I don't have any official information to confirm that. From observation, calling `ToString` on `5.0999999999999996` will result in `5.1`, but calling `ToString` on `5.0999999995999996` will result in `5.0999999996`, which is what lead me to this hypothesis. – ProgrammingLlama Feb 13 '20 at 02:35
  • 1
    You know how to print the full precision value which matches what you got from C++. It's not clear what more there is to your question. Perhaps you could post a new one if you have other outstanding issues? – ProgrammingLlama Feb 13 '20 at 02:57
  • 1
    How do you get those results? Where do they come from? What's the C# code? What's the C++ code? What does it have to do with your original question? You shouldn't really edit a question such that it invalidates existing answers, which this edit seems to do. – ProgrammingLlama Feb 13 '20 at 03:02
  • @John, sorry I didn't change my question at all, for the commercial reasons I couldn't post the code here, If I could, I already did that. As I said, I am rewriting the method from C++ to C#, and the codes are almost the same, except for the pointer and const factors etc. I didn't know why do you guys focus on the precision changes in the double value and argue whether they are the same, my question is: How can I make the calculation results to be the same. – Rei Ryu Feb 13 '20 at 03:11
  • 2
    If we can't see the computation and the process that brought you there, the best we can offer is bland generalizations. You could have stumbled over a subtle difference between the languages that goes above and beyond the inexactness of floating point numbers, but there is no way to know. – user4581301 Feb 13 '20 at 03:18
  • 3
    Suggestion: Make what we call a [mcve]. A little program, two in this case, that demonstrates the problem with as little added fluff as possible. Unless the problem is really, really subtle and requires great detail to reproduce, the MRE will look nothing like the code you need to protect from prying eyes. – user4581301 Feb 13 '20 at 03:25
  • @user4581301 That's a good idea, I am on the way! – Rei Ryu Feb 13 '20 at 03:30
  • By the way, I've tried a more complex calculation in C++ and C#, before outputting the result as hexadecimal in both and the result is the same on both sides. [C++ sample](http://cpp.sh/9m3oq) and [C# sample](https://rextester.com/UTY88905) – ProgrammingLlama Feb 13 '20 at 05:57
  • 2
    After discussing with my team lead, I was told it is ok to regard them as the same result with 3 digits after the decimal point. So the question is closed. – Rei Ryu Feb 13 '20 at 06:41

2 Answers2

1

It's a display issue - the actual value is as you expect and matches your C++ code. Try this code to see the approximate1 value stored:

double a = 4.9; double b = 5.1;
Console.WriteLine(a.ToString("G20"));
Console.WriteLine(b.ToString("G20"));

The result is:

4.9000000000000004

5.0999999999999996

See here to learn more about why I used G20, and what the other number format strings are.


1 I say approximate value because computers can only store fractions composed of 1/pow(2, n). For example 0.75 is 1/2 + 1/4, so this can be represented accurately. In the same way that we can't accurately represent 1/3 in base 10 (we might write 0.3, 0.33, 0.333, 0.3333, etc.), you can't represent some fractions in base 2 (binary) because they can't be composed of powers of two. See this question for more on that.

Community
  • 1
  • 1
ProgrammingLlama
  • 36,677
  • 7
  • 67
  • 86
-1

Short answer, probably because of compiler optimisations.

Following the IEEE Float spec to the letter would produce exactly the same results. But compilers often make decisions to sacrifice correctness for speed. Applying algebraic rearrangements to your code, fusing multiple operations together, all kinds of optimisations will change the result.

Most C compilers provide compiler flags that allow you to tune which of these optimisations are allowed. I'm not aware if C# provides any explicit guarantees.

Jeremy Lakeman
  • 9,515
  • 25
  • 29