4

I'm using the following piece of code and under some mysterious circumstances the result of the addition is not as it's supposed to be:

double _west = 9.482935905456543;
double _off = 0.00000093248155508263153;
double _lon = _west + _off;

// check for the expected result
Debug.Assert(_lon == 9.4829368379380981);
// sometimes i get 9.48293685913086 for _lon (which is wrong)

I'm using some native DLLs within my application and i suspect that some DLL is responsible for this 'miscalculation', but i need to figure out which one. Can anyone give me a hint how to figure out the root of my problem?

Andreas Roth
  • 699
  • 2
  • 9
  • 30
  • What I am saying here applies to double as well: http://stackoverflow.com/questions/1193554/trouble-with-float-in-objective-c/1193607#1193607 – Ralph M. Rickenbach Jul 28 '09 at 12:11
  • The root of the problem is caused by a wrong setting of the floating-point precision. Someone sets the floating point precision to 24-bits and this causes the calculation to be wrong. Using _fpreset or _controlfp (of the MSVC runtime dll) can correct this, but it still remains the mystery who sets this precision in the first place? – Andreas Roth Jul 29 '09 at 15:10
  • another example: 0.8 + 0.4 = 1.2000000000000002 – Mahmoud Amini Arjmand Nov 24 '19 at 08:02
  • Other simple examples: `0.1 * 0.1 = 0.010000000000000002`, `0.1 + 0.2 = 0.30000000000000004`, `0.1 * 0.2 = 0.020000000000000004`, `0.1 - 0.3 = -0.19999999999999998`, `0.2 + 0.1 = 0.30000000000000004`, `0.2 * 0.1 = 0.020000000000000004`, `0.2 * 0.2 = 0.04000000000000001`, `0.2 - 0.3 = -0.09999999999999998`, `0.3 - 0.1 = 0.19999999999999998`, `0.3 - 0.2 = 0.09999999999999998` :) – Robert Synoradzki Feb 19 '22 at 10:06

5 Answers5

12

double is not completely accurate, try using decimal instead

The advanteage of using double and float over decimal is performance

terjetyl
  • 9,497
  • 4
  • 54
  • 72
  • 1
    -1 How can a `Decimal` offer better performance over a `Double`? Your CPU knows how to handle `Singles` and `Doubles` but all operations on a `Decimal` must happen in memory which is slower. – Andrew Hare Jul 28 '09 at 12:25
  • 3
    @TT - I don't know how I did it but I completely misread your answer - I apologize! (-1) removed and +1 for pointing out performance concerns! – Andrew Hare Jul 28 '09 at 12:59
2

At first I thought this was a rounding error but actually it is your assertion that is wrong. Try adding the entire result of your calculation without any arbitrary rounding on your part.

Try this:

using System;

class Program
{
    static void Main()
    {
        double _west = 9.482935905456543;
        double _off = 0.00000093248155508263153;
        double _lon = _west + _off;

        // check for the expected result
        Console.WriteLine(_lon == 9.48293683793809808263153);       
    }
}

In the future though it is best to use System.Decimal in cases where you need to avoid rounding errors that are usually associated with the System.Single and System.Double types.

That being said, however, this is not the case here. By arbitrarily rounding the number at a given point you are assuming that the type will also round at that same point which is not how it works. Floating point numbers are stored to their maximum representational capacity and only once that threshold has been reached does rounding take place.

Andrew Hare
  • 344,730
  • 71
  • 640
  • 635
  • I tried using decimals, but converting a double into a decimal failed, because decimal automatically rounded the given value. How could this be avoided? – Andreas Roth Jul 28 '09 at 12:02
1

The problem is that Double only has precision of 15 - 16 digits (and you seem to need more precision in your example) whereas Decimal has precision to 28 - 29. How are you converting between Double and Decimal?

Paul Lydon
  • 958
  • 6
  • 6
0

You are being bitten by rounding and precision problems. See this. Decimal might help. Go here for details on conversions and rounding.

From MSDN:

When you convert float or double to decimal, the source value is converted to decimal representation and rounded to the nearest number after the 28th decimal place if required. Depending on the value of the source value, one of the following results may occur:

If the source value is too small to be represented as a decimal, the result becomes zero.

If the source value is NaN (not a number), infinity, or too large to be represented as a decimal, an OverflowException is thrown.

Community
  • 1
  • 1
n8wrl
  • 19,439
  • 4
  • 63
  • 103
0

You cannot represent every floating point number in the decimal system with a floating point in a binary system accurately, this isn't even directly related to how "small" the decimal number is, some numbers just don't "fit" in base-2 nicely.

Using a longer bit width can help in most cases, but not always.

To specify your constants in Decimal (128-bit floating point ) precision, use this declaration:

decimal _west = 9.482935905456543m;
decimal _off = 0.00000093248155508263153m;
decimal _lon = _west + _off;
Kenan E. K.
  • 13,955
  • 3
  • 43
  • 48