|
When using floating-point numbers (Single data type (Visual Basic) and Double data type (Visual Basic)), remember that they are stored as binary fractions. This means that for any number of non-binary fractions (of the form k / (2 ^ n, where k and n are integers), floating-point numbers cannot store their exact representation. For example, 0.5 (= 1/ 2) and 0.3125 (= 5/16) can be saved as accurate values, while 0.2 (= 1/5) and 0.3 (= 3/10) can only be approximate values.
Because of this imprecision, you cannot expect accurate results when dealing with floating-point values. Specifically, two values that are theoretically equal may have slightly different representations.
Compare floating point numbers
Use the Abs method of the Math class in the System namespace to calculate the absolute value of the difference between the quantities.
Determine the maximum acceptable difference so that if the difference between the two quantities does not exceed this value, you can consider that the two quantities are actually equal.
Compare the absolute value of the difference with the acceptable difference.
The following example demonstrates a true and false comparison of two Double values.
Visual Basic Copy Code
Dim oneThird As Double = 1.0 / 3.0
Dim pointThrees As Double = 0.333333333333333
'The following comparison does not indicate equality.
Dim exactlyEqual As Boolean = (oneThird = pointThrees)
'The following comparison indicates equality.
Dim closeEnough As Double = 0.000000000000001
Dim absoluteDifference As Double = Math.Abs(oneThird-pointThrees)
Dim practicallyEqual As Boolean = (absoluteDifference <closeEnough)
MsgBox("1.0 / 3.0 is represented as "&oneThird.ToString("G17") _
&vbCrLf&"0.333333333333333 is represented as "_
&pointThrees.ToString("G17") _
&vbCrLf&"Exact comparison generates "&CStr(exactlyEqual) _
&vbCrLf&"Acceptable difference comparison generates "_
&CStr(practicallyEqual))
The above example uses the ToString method of the Double structure, so it can specify a higher precision than when using the CStr keyword. The default precision is 15 digits, but the "G17" format expands it to 17 digits.
The Mod operator does not return accurate results
Due to the inaccuracy of floating-point storage, if at least one operand is a floating-point number, the Mod operator (Visual Basic) may return unexpected results.
The Decimal data type (Visual Basic) does not use floating-point representation. Many numbers that are imprecise in Single and Double are exact numbers in Decimal (for example, 0.2 and 0.3). Although the floating-point representation is faster in arithmetic operations than the Decimal representation, it may be worth the performance degradation in exchange for the precision improvement.
Find the integer remainder of the floating point number
Declare the variable as Decimal.
Use the text type character D to coerce the text to Decimal in case the value of the text is too large relative to the Long data type.
The following example demonstrates the potential inaccuracy of floating-point operands.
Visual Basic Copy Code
Dim two As Double = 2.0
Dim zeroPointTwo As Double = 0.2
Dim quotient As Double = two / zeroPointTwo
Dim doubleRemainder As Double = two Mod zeroPointTwo
MsgBox("2.0 is represented as "&two.ToString("G17") _
&vbCrLf&"0.2 is represented as "&zeroPointTwo.ToString("G17") _
&vbCrLf&"2.0 / 0.2 generates ""ient.ToString("G17") _
&vbCrLf&"2.0 Mod 0.2 generates "_
&doubleRemainder.ToString("G17"))
Dim decimalRemainder As Decimal = 2D Mod 0.2D
MsgBox("2.0D Mod 0.2D generates "&CStr(decimalRemainder))
The above example uses the ToString method of the Double structure, so it can specify a higher precision than when using the CStr keyword. The default precision is 15 digits, but the "G17" format expands it to 17 digits.
Since zeroPointTwo is Double, the value 0.2 it represents is an infinitely repeated binary fraction (the stored value is 0.20000000000000001). Dividing 2.0 by this amount will give 9.9999999999999995 with a remainder of 0.19999999999999991.
In the expression of decimalRemainder, the text type character D coerces both operands to Decimal, so that 0.2 will have an accurate representation. Therefore, the Mod operator will get the expected remainder 0.0.
Note that declaring decimalRemainder as Decimal is not enough. You must also cast the text to Decimal, otherwise they will default to Double, and decimalRemainder will receive inaccurate values just like doubleRemainder.
MSDN 2005
ms-help://MS.MSDNQTR.v80.chs/MS.MSDN.v80/MS.VisualStudio.v80.chs/dv_vbalr/html/90040d67-b630-4125-a6ae-37195b079042.htm |
|