Hi,
 
I've had a lot of problems with decimal values very near integer values
not being what they look like. The latest trouble I've had occurred when
writing a simple histogram function. I calculated the index into a block
and wound up with a value that was about 1 - 2e-16. Since Rebol does
imprecise comparisons, such a value looks like 1 until you try to use it:
 
>> index: 1 - 2e-16
== 1
>> index = 1
== true
>> pick [1 2 3 4 5] index
== none
>> to-integer index
== 0
 
Also:
 
>> index2: 2 - 2e-16
== 2
>> pick [1 2 3 4 5] index2
== 1
 
I think Rebol is trying help us by "shielding" us from floating-point
round-off errors, but this means that when the problems pop up farther down
the road, they can be really hard to pin down. Rebol does have STRICT-EQUAL?
and == , but those just detect the difference between integer and decimal
datatypes, and can return false when the values really are equal:
 
>> index == 1
== false           ; cool, but ...
>> 1.0 == 1
== false
 
I've been doing some translations from Numerical Recipes in C into Rebol, and
found that I've had to roll all my own comparison functions. For a lot of
calculations, results like
 
>> 1e-16 = 1e-32
== true
>> 1e-16 == 1e-32
== true
 
are bizarre! I'm sending this to feedback as well, but I'd be very interested
to hear if anyone on the list has opinions on this topic.
 
Thanks,
Eric
 
PS - Has anyone ever found a use for =? SAME? or STRICT-NOT-EQUAL?   ?
 
In case anyone's interested, here's how I put together the comparison
functions:
 
cmp: func[
    {comparison: returns 1 if v1 > v2, 0 if v1 = v2, -1 if v1 < v2}
    v1 v2 /local diff
][
    either any-string? v1 [
        v1: to-binary v1    ; allows case-sensitive string comparison
        v2: to-binary v2
        either v1 = v2 [0][either v1 > v2 [1][-1]]
    ][
        either number? v1 [
            either zero? diff: v1 - v2 [0][
                while [0 = diff][diff: diff * 256]  ; magnify the difference
                either diff > 0 [1][-1]
            ]
        ][either v1 > v2 [1][either v2 = v1 [0][-1]]]  ; default
    ]
]
 
gt: func [{returns TRUE if the first one is greater} v1 v2][
    either 1 = cmp v1 v2 [true][false]
]   ; and so on ...
 
>> gt 1e-16 1e-32
== true

Reply via email to