Hi Torsten,
Dear all,
I came across some behaviour of floats in a C-style loop which I don't
understand. In the following test function, I want to collect N floats
between 0.0 and 1.0, including these boundaries.
fun {SampleInts N}
Incr = 1.0 / {IntToFloat N-1}
in
for X in 0.0;X=<1.0;X+Incr
collect:C
do {C X}
end
end
{SampleInts 10}
% -> [0.0, 0.11111 ... 0.88889]
However, the last value (i.e., 1.0) is left out in the result. It appears that
this last value is actually already slightly greater then 1.0 (due to the
typical float problems I assume). So, I came up with the following hack,
where I test against a number which is slightly larger than 1.0.
Sure, you would get similar results in C.
fun {SampleInts2 N}
Incr = 1.0 / {IntToFloat N-1}
Max = 1.0+1.0E~13
in
for X in 0.0;X=<Max;X+Incr
collect:C
do {C X}
end
end
{SampleInts2 10}
% -> [0.0, 0.11111 ... 0.88889 1.0]
Now, the surprising aspect for me is that with such a hack, the last element
is indeed displayed as 1.0 and not anything slightly larger.
I should perhaps mention that I am porting some Common Lisp program to Oz,
where the equivalent of the first function works totally fine in Lisp. So, is
there some magic at the Lisp side going on (Lisp supports ratios, not only
floats), and the Oz behaviour is the usual thing to happen when you use
floats? Any idea, how to write a version of SampleInts which works for an
arbitrary high N?
You could try some custom rounding of the sum in each iteration if your
increments are just slightly imprecise, like rouding to 6 valid digits
when you're using <0, 1> increments. Of course, this can not be used in
general, you have to think of how many numbers you have and if rounding
does not corrupt your sequence...
A nice alternative is using XRI, where each float constant can be
represented by an interval containing the (precise) number. So you get
interval arithmetics and you can test whether "1." is in or out of the
resulting interval.
Yet another alternative is expressing each element of your sequence like
Ei = ((Mx - Mn) * I / N) + Mn
BTW, did you notice that you're shadowing the built-in Max variable? See
ozc --warnshadow
Best,
Filip
_________________________________________________________________________________
mozart-users mailing list
[email protected]
http://www.mozart-oz.org/mailman/listinfo/mozart-users