[BUG] round a Float

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

[BUG] round a Float

Nicolas Cellier
I checked in VWNC 7.8, and it appears to suffer exactly from same bug than
explained here
http://stackoverflow.com/questions/9902968/why-does-math-round0-49999999999999994-return-1

For example, try

(0.5d - (2.0d raisedTo: -54)) < 0.5d.
(0.5d - (2.0d raisedTo: -54)) rounded

See also
http://stackoverflow.com/questions/485525/round-for-float-in-c/11074691#11074691

Is it fixed in 7.9?

Nicolas

_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Re: [BUG] round a Float

Samuel S. Shuster-2
Nicolas,

I know just about nothing about the details of the rounding of numbers in the IEEE number world.

That said, in 7.9:

> (0.5d - (2.0d raisedTo: -54)) < 0.5d.
        true
> (0.5d - (2.0d raisedTo: -54)) rounded
        1
0.5d < 0.5d
        false

So at this time, 7.9 is the same as 7.8

But I went a bit farther and found the following are interesting answers also:

(0.5s - (2.0s raisedTo: -54)) < 0.5s.
        true
(0.5s - (2.0s raisedTo: -54)) rounded  
        0
0.5s < 0.5s.
        false

But that's must my 0.02s.

                                And So It Goes
                                     Sames
______________________________________________________________________

Samuel S. Shuster [|]
VisualWorks Engineering, Code Management Project




_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Re: [BUG] round a Float

Andres Valloud-6
In reply to this post by Nicolas Cellier
Huh... yeah, that looks like it's messed up... I'll add it to the queue
of things to deal with in the next IEEE work batch.

On 7/21/2012 12:56 PM, Nicolas Cellier wrote:

> I checked in VWNC 7.8, and it appears to suffer exactly from same bug than
> explained here
> http://stackoverflow.com/questions/9902968/why-does-math-round0-49999999999999994-return-1
>
> For example, try
>
> (0.5d - (2.0d raisedTo: -54)) < 0.5d.
> (0.5d - (2.0d raisedTo: -54)) rounded
>
> See also
> http://stackoverflow.com/questions/485525/round-for-float-in-c/11074691#11074691
>
> Is it fixed in 7.9?
>
> Nicolas
>
> _______________________________________________
> vwnc mailing list
> [hidden email]
> http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
>
_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Re: [BUG] round a Float

Martin McClure-3
On 07/21/2012 04:08 PM, Andres Valloud wrote:
> (0.5d - (2.0d raisedTo: -54)) rounded

On Windows, this answers 1.
On Linux, it answers the (correct) 0.

Regards,

-Martin
_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Re: [BUG] round a Float

Paul Baumann
In reply to this post by Andres Valloud-6
Nicholas,

This issue has been discussed to death over decades. The answer always comes back to "it is correct by IEEE standards" and the standard sucks.

VW 7.5 image with 7.6 VM:

(0.5 - (2.0 raisedTo: -54)) < 0.5.
 false
(0.5 - (2.0 raisedTo: -54)) rounded
 1

(0.5d - (2.0d raisedTo: -54)) < 0.5d.
 true
(0.5d - (2.0d raisedTo: -54)) rounded
 1

((1/2) - (2 raisedTo: -54)) < (1/2).
 true
((1/2) - (2 raisedTo: -54)) rounded
 0

64-bit GS/S (floats are now always doubles):

(0.5 - (2.0 raisedTo: -54)) < 0.5.
 true
(0.5 - (2.0 raisedTo: -54)) rounded
 1

((1/2) - (2 raisedTo: -54)) < (1/2).
 true
((1/2) - (2 raisedTo: -54)) rounded
 0

Floats in VW once seemed to compensate for IEEE float imprecision like magic to give a logically correct answer. Not anymore. Both GS and VW are now fully compliant to the standard and can't give a more correct answer than C.

The way GS displays floats is usually irritating, but it is nice that it reveals why the computations answered as they had:

(0.5 - (2.0 raisedTo: -54))
 4.9999999999999994E-01
0.5
 5.0000000000000000E-01

This returns the noise from 64-bit GS floats:

limitOfDecimalPrecision
        "Extension used to avoid float imprecision noise. Answer a value beyond
         which would be considered noise for this float implementation."

        0.0 == self ifTrue: [^0.0].
        "^10.0 raisedTo: (self abs log10 asInteger - 13)."
        "Same as above, but method becomes 28% faster."
        ^#(     1.0E-29 1.0E-28 1.0E-27 1.0E-26 1.0E-25 1.0E-24 1.0E-23 1.0E-22 1.0E-21 1.0E-20
                1.0E-19 1.0E-18 1.0E-17 1.0E-16 1.0E-15 1.0E-14 1.0E-13 1.0E-12 1.0E-11 1.0E-10
                1.0E-09 1.0E-08 1.0E-07 1.0E-06 1.0E-05 1.0E-04 1.0E-03 1.0E-02 1.0E-01 1.0E-00
                1.0E+01 1.0E+02 1.0E+03 )
                        at: 30 + (self abs log10 asInteger - 13).

This shows identical precision limits for the two values above:

(0.5 - (2.0 raisedTo: -54)) limitOfDecimalPrecision
 1.0000000000000000E-13
0.5 limitOfDecimalPrecision
 1.0000000000000000E-13

So then just round the to the limit of precision and be done with it:

roundoff
        "Extension by Paul Baumann 2012.03.16. Answer a 'unit roundoff'
         of the float imprecision (machine epsilon) that the receiver may carry from the
         previous calculation. It attempts to return a value that would be equal
         to a double created from string/compiled float value (like '0.1' asFloat).
         To understand the problem read: http://en.wikipedia.org/wiki/Floating_point

                0.1 = ('0.1' asFloat).
                         true
                10.0 = (0.1 + 9.9).
                         true
                0.1 = (10.0 - 9.9).
                         false
                0.1 = (10.0 - 9.9) roundoff.
                         true
                (0.1 - 9.9) = ((10.0 - 9.9) - 9.9).
                         true
                (0.1 - 9.9) = ((10.0 - 9.9) - 9.9) roundoff.
                         true
                (10 - (99 /10)) = (10.0 - 9.9).
                         false
                (10 - (99 /10)) = (10.0 - 9.9) roundoff.
                         true
                (10.0 - (99 /10)) = (10.0 - 9.9) roundoff.
                         false
                (10.0 - (99 /10)) roundOff = (10.0 - 9.9) roundoff.
                         true
        "

        0.0 == self ifTrue: [^0.0].
        ^self roundTo: self limitOfDecimalPrecision

Using the #roundoff method now gives:

(0.5 - (2.0 raisedTo: -54)) roundoff
 5.0000000000000000E-01
0.5 roundoff
 5.0000000000000000E-01

Looks good, but not a perfect solution though. Incremental imprecision that can't be reliably cut after it is introduced. It is impractical to have all the application code roundoff from operations.

I accept that the code works according to IEEE standards and that floats are a bad choice for most applications. IEEE floats are more for efficiency than precision. At some point you end up changing to something that gives a useful answer.

Paul Baumann



-----Original Message-----
From: [hidden email] [mailto:[hidden email]] On Behalf Of Andres Valloud
Sent: Saturday, July 21, 2012 19:08
To: [hidden email]
Subject: Re: [vwnc] [BUG] round a Float

Huh... yeah, that looks like it's messed up... I'll add it to the queue
of things to deal with in the next IEEE work batch.

On 7/21/2012 12:56 PM, Nicolas Cellier wrote:

> I checked in VWNC 7.8, and it appears to suffer exactly from same bug than
> explained here
> http://stackoverflow.com/questions/9902968/why-does-math-round0-49999999999999994-return-1
>
> For example, try
>
> (0.5d - (2.0d raisedTo: -54)) < 0.5d.
> (0.5d - (2.0d raisedTo: -54)) rounded
>
> See also
> http://stackoverflow.com/questions/485525/round-for-float-in-c/11074691#11074691
>
> Is it fixed in 7.9?
>
> Nicolas
>
> _______________________________________________
> vwnc mailing list
> [hidden email]
> http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
>
_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc


This message may contain confidential information and is intended for specific recipients unless explicitly noted otherwise. If you have reason to believe you are not an intended recipient of this message, please delete it and notify the sender. This message may not represent the opinion of IntercontinentalExchange, Inc. (ICE), its subsidiaries or affiliates, and does not constitute a contract or guarantee. Unencrypted electronic mail is not secure and the recipient of this message is expected to provide safeguards from viruses and pursue alternate means of communication where privacy or a binding message is desired.


_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Re: [BUG] round a Float

Nicolas Cellier
Paul Baumann <paul.baumann <at> theice.com> writes:

>
> Nicholas,
>
> This issue has been discussed to death over decades. The answer always comes
back to "it is correct by IEEE

> standards" and the standard sucks.
>
> VW 7.5 image with 7.6 VM:
>
> (0.5 - (2.0 raisedTo: -54)) < 0.5.
>  false
> (0.5 - (2.0 raisedTo: -54)) rounded
>  1
>
> (0.5d - (2.0d raisedTo: -54)) < 0.5d.
>  true
> (0.5d - (2.0d raisedTo: -54)) rounded
>  1
>
> ((1/2) - (2 raisedTo: -54)) < (1/2).
>  true
> ((1/2) - (2 raisedTo: -54)) rounded
>  0
>
> 64-bit GS/S (floats are now always doubles):
>
> (0.5 - (2.0 raisedTo: -54)) < 0.5.
>  true
> (0.5 - (2.0 raisedTo: -54)) rounded
>  1
>
> ((1/2) - (2 raisedTo: -54)) < (1/2).
>  true
> ((1/2) - (2 raisedTo: -54)) rounded
>  0
>
> Floats in VW once seemed to compensate for IEEE float imprecision like magic
to give a logically correct
> answer. Not anymore. Both GS and VW are now fully compliant to the standard
and can't give a more correct
> answer than C.
>

Hi Paul,
if you open a final draft of ISO/IEC 10967-2 standard,
http://www.open-std.org/jtc1/sc22/wg11/docs/n462.pdf for example,
then you'll find in §5.2.4 a definition of float rounding function.
    rounding_F(x) = round(x),
where round is the exact mathematical function.

The case of exact tie might be implementation defined (the function nearest_F is
implementation defined as described in §5.2.1, but I did not find the exact
definition of round in the draft).
So round(0.5) might be 0 or 1 depending on implementation (away from zero, or
unbiased, generally to nearest even).
But for the predecessor of 0.5, no doubt, the result MUST be zero if you comply
to the standard...

C99 function round() and C++ 2011 round() are compliant, if you have a recent
gcc, you can check with
    printf( "%f\n",round(0.49999999999999994));

Also note from appendix B.5.2.4, the rounding function is symmetric,
    rounding_F(x) = neg_F(rounding_F(neg_F(x)))

Though, in Smalltalk, we rather implement rounding_F->I(x), and that's a good
thing because we don't have to deal with negative zeroes.

Of course, all this is quite germane and may not matter for a majority of us,
but there is no reason to go against the standards:
1) there is no reason why rounding would be inexact;
2) beside, the fact that some floating point operation are not exact is not a
license to spoil the precision gratuitously;
3) the only reason to let the precision degrade is to avoid very costly
calculus, which is again not the case for rounding.

Current status is just the conjunction of ignorance and laziness
(I say laziness because floor(x+copysign(0.5,x)) is a cheap and easy solution).
After this post, I hope we can't invoke ignorance again, only laziness remains.
So if GS is not compliant, i invite you to open an issue as well...

Cheers

Nicolas

_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Re: [BUG] round a Float

Andres Valloud-6
In reply to this post by Andres Valloud-6
This is fixed now, and should be included in the development 7.10 builds
shortly.

On 7/21/2012 4:08 PM, Andres Valloud wrote:

> Huh... yeah, that looks like it's messed up... I'll add it to the queue
> of things to deal with in the next IEEE work batch.
>
> On 7/21/2012 12:56 PM, Nicolas Cellier wrote:
>> I checked in VWNC 7.8, and it appears to suffer exactly from same bug than
>> explained here
>> http://stackoverflow.com/questions/9902968/why-does-math-round0-49999999999999994-return-1
>>
>> For example, try
>>
>> (0.5d - (2.0d raisedTo: -54)) < 0.5d.
>> (0.5d - (2.0d raisedTo: -54)) rounded
>>
>> See also
>> http://stackoverflow.com/questions/485525/round-for-float-in-c/11074691#11074691
>>
>> Is it fixed in 7.9?
>>
>> Nicolas
>>
>> _______________________________________________
>> vwnc mailing list
>> [hidden email]
>> http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
>>
> _______________________________________________
> vwnc mailing list
> [hidden email]
> http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
>
_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc
Reply | Threaded
Open this post in threaded view
|

Re: [BUG] round a Float

Andres Valloud-6
In reply to this post by Martin McClure-3
Just looking at old email here... this is fixed now.

On 7/24/12 4:47 PM, Martin McClure wrote:

> On 07/21/2012 04:08 PM, Andres Valloud wrote:
>> (0.5d - (2.0d raisedTo: -54)) rounded
>
> On Windows, this answers 1.
> On Linux, it answers the (correct) 0.
>
> Regards,
>
> -Martin
>
_______________________________________________
vwnc mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/vwnc