开发者

Addition of Double values inconsistent

开发者 https://www.devze.com 2023-03-03 10:24 出处:网络
I came across following issue while developing some engineering rule value engine using eval(...开发者_运维百科) implementation.

I came across following issue while developing some engineering rule value engine using eval(...开发者_运维百科) implementation.

    Dim first As Double = 1.1
    Dim second As Double = 2.2
    Dim sum As Double = first + second
     If (sum = 3.3) Then
        Console.WriteLine("Matched")
    Else
        Console.WriteLine("Not Matched")
    End If

'Above condition returns false because sum's value is 3.3000000000000003 instead of 3.3

It looks like 15th digit is round-tripped. Someone may give better explanation on this pls.

Is Math.Round(...) only solution available OR there is something else also I can attempt?


You are not adding decimals - you are adding up doubles.

Not all doubles can be represented accurately in a computer, hence the error. I suggest reading this article for background (What Every Computer Scientist Should Know About Floating-Point Arithmetic).

Use the Decimal type instead, it doesn't suffer from these issues.

Dim first As Decimal = 1.1
Dim second As Decimal = 2.2
Dim sum As Decimal= first + second
 If (sum = 3.3) Then
    Console.WriteLine("Matched")
Else
    Console.WriteLine("Not Matched")
End If


that's how the double number work in PC. The best way to compare them is to use such a construction

if (Math.Abs(second - first) <= 1E-9)
 Console.WriteLine("Matched")

instead if 1E-9 you can use another number, that would represent the possible error in comparison.


Equality comparisons with floating point operations are always inaccurate because of how fractional values are represented within the machine. You should have some sort of epsilon value by which you're comparing against. Here is an article that describes it much more thoroughly:

http://www.cygnus-software.com/papers/comparingfloats/Comparing%20floating%20point%20numbers.htm

Edit: Math.Round will not be an ideal choice because of the error generated with it for certain comparisons. You are better off determining an epsilon value that can be used to limit the amount of error in the comparison (basically determining the level of accuracy).


A double uses floating-point arithmetic, which is approximate but more efficient. If you need to compare against exact values, use the decimal data type instead.


In C#, Java, Python, and many other languages, decimals/floats are not perfect. Because of the way they are represented (using multipliers and exponents), they often have inaccuracies. See http://www.yoda.arachsys.com/csharp/decimal.html for more info.


From the documentaiton: http://msdn.microsoft.com/en-us/library/system.double.aspx

Floating-Point Values and Loss of Precision

Remember that a floating-point number can only approximate a decimal number, and that the precision of a floating-point number determines how accurately that number approximates a decimal number. By default, a Double value contains 15 decimal digits of precision, although a maximum of 17 digits is maintained internally. The precision of a floating-point number has several consequences:

Two floating-point numbers that appear equal for a particular precision might not compare equal because their least significant digits are different.

A mathematical or comparison operation that uses a floating-point number might not yield the same result if a decimal number is used because the floating-point number might not exactly approximate the decimal number.

A value might not roundtrip if a floating-point number is involved. A value is said to roundtrip if an operation converts an original floating-point number to another form, an inverse operation transforms the converted form back to a floating-point number, and the final floating-point number is equal to the original floating-point number. The roundtrip might fail because one or more least significant digits are lost or changed in a conversion.

In addition, the result of arithmetic and assignment operations with Double values may differ slightly by platform because of the loss of precision of the Double type. For example, the result of assigning a literal Double value may differ in the 32-bit and 64-bit versions of the .NET Framework. The following example illustrates this difference when the literal value -4.42330604244772E-305 and a variable whose value is -4.42330604244772E-305 are assigned to a Double variable. Note that the result of the Parse(String) method in this case does not suffer from a loss of precision.


THis is a well known problem with floating point arithmatic. Look into binary coding for further details.

Use the type "decimal" if that will fit your needs.

But in general, you should never compare floating point values to constant floating point values with the equality sign.

Failing that, compare to the number of places that you want to compare to (e.g. say it is 4 then you would go (if sum > 3.2999 and sum < 3.3001)

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号