math.round function has a bug?
-
I'll try to explain : look this example : Module Module1 Sub Main() Dim num AsDouble = 1.25 Console.WriteLine(Math.Round(num, 1, MidpointRounding.AwayFromZero)) num = 1.225 Console.WriteLine(Math.Round(num, 2, MidpointRounding.AwayFromZero)) num = 1.2225 Console.WriteLine(Math.Round(num, 3, MidpointRounding.AwayFromZero)) num = 1.22225 Console.WriteLine(Math.Round(num, 4, MidpointRounding.AwayFromZero)) num = 1.222225 Console.WriteLine(Math.Round(num, 5, MidpointRounding.AwayFromZero)) num = 1.2222225 Console.WriteLine(Math.Round(num, 6, MidpointRounding.AwayFromZero)) EndSub End Module The output of this sample console application is : 1,3 1,23 1,223 1,2223 1,22222 1,222223 Is there something wrong ? In my application I must use five decimal digits and this round method. Regards Andrea
-
I'll try to explain : look this example : Module Module1 Sub Main() Dim num AsDouble = 1.25 Console.WriteLine(Math.Round(num, 1, MidpointRounding.AwayFromZero)) num = 1.225 Console.WriteLine(Math.Round(num, 2, MidpointRounding.AwayFromZero)) num = 1.2225 Console.WriteLine(Math.Round(num, 3, MidpointRounding.AwayFromZero)) num = 1.22225 Console.WriteLine(Math.Round(num, 4, MidpointRounding.AwayFromZero)) num = 1.222225 Console.WriteLine(Math.Round(num, 5, MidpointRounding.AwayFromZero)) num = 1.2222225 Console.WriteLine(Math.Round(num, 6, MidpointRounding.AwayFromZero)) EndSub End Module The output of this sample console application is : 1,3 1,23 1,223 1,2223 1,22222 1,222223 Is there something wrong ? In my application I must use five decimal digits and this round method. Regards Andrea
No, there isn't anything wrong with the
Round
method. The problem is your expectations on thedouble
data type. You think that you are putting the exact value1.222225
in the variable, but that number (as most numbers) can not be exactly represented as adouble
. What you are actually putting in the variable is something very close to that value, something like1.22222499999834
, which does of course round to1.22222
.Despite everything, the person most likely to be fooling you next is yourself.
-
I'll try to explain : look this example : Module Module1 Sub Main() Dim num AsDouble = 1.25 Console.WriteLine(Math.Round(num, 1, MidpointRounding.AwayFromZero)) num = 1.225 Console.WriteLine(Math.Round(num, 2, MidpointRounding.AwayFromZero)) num = 1.2225 Console.WriteLine(Math.Round(num, 3, MidpointRounding.AwayFromZero)) num = 1.22225 Console.WriteLine(Math.Round(num, 4, MidpointRounding.AwayFromZero)) num = 1.222225 Console.WriteLine(Math.Round(num, 5, MidpointRounding.AwayFromZero)) num = 1.2222225 Console.WriteLine(Math.Round(num, 6, MidpointRounding.AwayFromZero)) EndSub End Module The output of this sample console application is : 1,3 1,23 1,223 1,2223 1,22222 1,222223 Is there something wrong ? In my application I must use five decimal digits and this round method. Regards Andrea
-
No, there isn't anything wrong with the
Round
method. The problem is your expectations on thedouble
data type. You think that you are putting the exact value1.222225
in the variable, but that number (as most numbers) can not be exactly represented as adouble
. What you are actually putting in the variable is something very close to that value, something like1.22222499999834
, which does of course round to1.22222
.Despite everything, the person most likely to be fooling you next is yourself.
Guffa wrote:
You think that you are putting the exact value 1.222225 in the variable, but that number (as most numbers) can not be exactly represented as a double. What you are actually putting in the variable is something very close to that value, something like 1.22222499999834, which does of course round to 1.22222.
Is there any function to increase a double by the smallest possible non-zero amount? I would expect one could do something like:
Function BumpDouble(ByVal Num As Double) As Double
Dim Delta, NewVal As DoubleDelta = Num / 36028797018963968 ' (2^55)
If Delta <> 0 Then
Do
NewVal = Num+Delta
Delta *= 2
Loop While Num = NewVal
Else
' Need special handling for really really small numbers
End If
Return NewVal
End FunctionBut that seems a bit hokey.
-
I'll try to explain : look this example : Module Module1 Sub Main() Dim num AsDouble = 1.25 Console.WriteLine(Math.Round(num, 1, MidpointRounding.AwayFromZero)) num = 1.225 Console.WriteLine(Math.Round(num, 2, MidpointRounding.AwayFromZero)) num = 1.2225 Console.WriteLine(Math.Round(num, 3, MidpointRounding.AwayFromZero)) num = 1.22225 Console.WriteLine(Math.Round(num, 4, MidpointRounding.AwayFromZero)) num = 1.222225 Console.WriteLine(Math.Round(num, 5, MidpointRounding.AwayFromZero)) num = 1.2222225 Console.WriteLine(Math.Round(num, 6, MidpointRounding.AwayFromZero)) EndSub End Module The output of this sample console application is : 1,3 1,23 1,223 1,2223 1,22222 1,222223 Is there something wrong ? In my application I must use five decimal digits and this round method. Regards Andrea
It looks to me liek the round function is working correctly for example for three decimal places 1.2225 since the last digit is 5 the number is rounded up to 1.223 my understanding of round is that a number is rounded down if the digits past the rounding point is 00 <= digits < 50 and rounded up if the digits past the rounding point is 50 <= digits < 100
Steve
-
It looks to me liek the round function is working correctly for example for three decimal places 1.2225 since the last digit is 5 the number is rounded up to 1.223 my understanding of round is that a number is rounded down if the digits past the rounding point is 00 <= digits < 50 and rounded up if the digits past the rounding point is 50 <= digits < 100
Steve
-
You are missing the point. Notice the value 1,22222 that seems to be rounded differently from the others.
Despite everything, the person most likely to be fooling you next is yourself.
Yeah actually single(float) and double are working the same way, it's not precise, because it's floating-point numbers representation. So it's a lot better and precise to use fixed-point number representation = Decimal in .Net :)
-- Everything is possible, even the impossible! ^_^
-
Guffa wrote:
You think that you are putting the exact value 1.222225 in the variable, but that number (as most numbers) can not be exactly represented as a double. What you are actually putting in the variable is something very close to that value, something like 1.22222499999834, which does of course round to 1.22222.
Is there any function to increase a double by the smallest possible non-zero amount? I would expect one could do something like:
Function BumpDouble(ByVal Num As Double) As Double
Dim Delta, NewVal As DoubleDelta = Num / 36028797018963968 ' (2^55)
If Delta <> 0 Then
Do
NewVal = Num+Delta
Delta *= 2
Loop While Num = NewVal
Else
' Need special handling for really really small numbers
End If
Return NewVal
End FunctionBut that seems a bit hokey.
Rather than try to compute
Delta
, useDouble.Epsilon
instead - then you could just doNum + Delta
. -
I'll try to explain : look this example : Module Module1 Sub Main() Dim num AsDouble = 1.25 Console.WriteLine(Math.Round(num, 1, MidpointRounding.AwayFromZero)) num = 1.225 Console.WriteLine(Math.Round(num, 2, MidpointRounding.AwayFromZero)) num = 1.2225 Console.WriteLine(Math.Round(num, 3, MidpointRounding.AwayFromZero)) num = 1.22225 Console.WriteLine(Math.Round(num, 4, MidpointRounding.AwayFromZero)) num = 1.222225 Console.WriteLine(Math.Round(num, 5, MidpointRounding.AwayFromZero)) num = 1.2222225 Console.WriteLine(Math.Round(num, 6, MidpointRounding.AwayFromZero)) EndSub End Module The output of this sample console application is : 1,3 1,23 1,223 1,2223 1,22222 1,222223 Is there something wrong ? In my application I must use five decimal digits and this round method. Regards Andrea
Use integer math with normalized integers and there is no problem. Added bonus - it's a gazillion time faster than floating point math. Divide by 10^5 before displaying to humans.
CICCIOLO69 wrote:
In my application I must use five decimal digits and this round method.
Teacher evidently wants you to think a little, knowing the problem exists.
Gary
-
Rather than try to compute
Delta
, useDouble.Epsilon
instead - then you could just doNum + Delta
.Stuart Dootson wrote:
Rather than try to compute Delta, use Double.Epsilon instead - then you could just do Num + Delta.
The smallest delta value for a given number will only equal Double.Epsilon if the number is very close to zero. In practice, it will always be equal to either the number divided by a particular power of two, or (if that division yields zero) Double.Epsilon; any assumption about the power of two in question, however, may break portability if future machines support higher-precision numerics.
-
I'll try to explain : look this example : Module Module1 Sub Main() Dim num AsDouble = 1.25 Console.WriteLine(Math.Round(num, 1, MidpointRounding.AwayFromZero)) num = 1.225 Console.WriteLine(Math.Round(num, 2, MidpointRounding.AwayFromZero)) num = 1.2225 Console.WriteLine(Math.Round(num, 3, MidpointRounding.AwayFromZero)) num = 1.22225 Console.WriteLine(Math.Round(num, 4, MidpointRounding.AwayFromZero)) num = 1.222225 Console.WriteLine(Math.Round(num, 5, MidpointRounding.AwayFromZero)) num = 1.2222225 Console.WriteLine(Math.Round(num, 6, MidpointRounding.AwayFromZero)) EndSub End Module The output of this sample console application is : 1,3 1,23 1,223 1,2223 1,22222 1,222223 Is there something wrong ? In my application I must use five decimal digits and this round method. Regards Andrea
The Round method does not use what most of the community expects the Round method to use with regards to its function. The reason being is because the Round method rounds to the nearest even integer, in a link following you will see it is termed: the bankers method. The Round method has two options: MidpointRounding.ToEven or MidpointRounding.AwayFromZero. Neither of these is exactly what a user may want to see. You may find a better here[^], at this URL (found by google) their is a custom function that should round based on what most of the community expects. I have no idea why Microsoft chose non-standard forms of the Round function.
Regards, Thomas Stockwell Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning. Visit my homepage Oracle Studios Discounted or Free Software for Students: DreamSpark - downloads.channel8.msdn.com MSDN Academic Alliance - www.msdnaa.com