RE: BUG! Erratic for loop behavior
- Posted by Henri.Goffin at sbs.be Mar 29, 2002
- 476 views
Hi! My 2P on the subject. I wrote this little program (see under) to help visualize the floating point (im-)precision in Eu floating point arithmetic. Basically it just outputs the results of some simple calculations with a lot of decimal positions but with 0's replaced by another char to improve readibility. >From this you can see that there is fluctuating relative error on the order of >10e-15 to 10e-16, sometimes positive, sometimes negative. By relative I mean the >ratio of the error to the magnitude of the number represented. IOW if you make >calculations with numbers on the order of 1 (say 1.5423/2.9997) you would expect >an absolute error on the order of 1e-15 or 0.000000000000001, and with numbers in >the millions the absolute error would be on the order of 1e-9 or 0.000000001 >(please count the 0's for me, i'm not sure). My question to the specialists out there: is it what one would expect given that it is claimed that Euphoria uses internally the 64-bit (double precision) IEEE floating point arithmetic? A challenge for the brave: write a program to see if the errors cancel out on the average or if there is a risk of cumulative errors, i.e. that the 1e-15 _relative_ precision becomes, say 1e-9, if you compute the sum of a million numbers. Now let's come back to the original message from Andy. As shocking as it seems at first sight this is completely normal. Don't forget that a for-loop contains implicitely a check for equality (if <var>=<end value>) on each cycle. Now even if Euphoria (or any other language) used 65536-bit precision floating point arithmetic you would still be at risk. The exact number of executions of the loop would still be uncertain. Why? Because the equality test is ultimately performed by the hardware in a strictly bit-for-bit way. And as we have seen there is always a chance that the internal representations of the current value of <var> and of <end value> will differ in at least one bit and it does not matter if it is the 65536-th one, the test will fail and you will get one cycle too much (or too few). The morale is: either use only integer values in for-loops or replace the for-loop with a while-loop. In the former case you would write: "for i = 311 to 342 by 1" and use i/10 inside the loop or equivalently "for i =1 to 32" and use (i+310)/10 In the latter case the while loop would read: i=31.1 while i < 34.3 do i += .1 end while Henri Goffin -------< start >-------- include get.e atom a function replace_in_string(sequence s, object o, object n) sequence so if atom(o) then so = repeat(o, length(s)) s += (s = so) * (n - o) return s else for i = 1 to length(o) do s = replace_in_string(s, o[i], n[i]) end for return s end if end function procedure Xprintf(atom nr, atom fl) sequence xp integer ix xp = sprintf("%d\t%30.25f\n",{nr, fl}) ix = match(".", xp) xp[ix+1..length(xp)] = replace_in_string(xp[ix+1..length(xp)], '0', '-') puts(1,xp) end procedure for k = 1 to 100 do system("cls",2) printf(1,"\n\nk = %d\n",{k}) a = 0 for i = 1 to 40 do Xprintf(i-1,a) a += .3 * k end for a = wait_key() end for