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

Reply via email to