Hello,
This:
outputs 0.95 at last line and not 1.
(now I use a integer from 0 to 100 and divide after)
Is it normal ?
a+
Vicnet
--
View this message in context: http://forum.openscad.org/Loop-precision-floating-point-precision-tp14642.html
Sent from the OpenSCAD mailing list archive at Nabble.com.
Yes this is normal.
In your loop:
for (t=[0.0:0.05:1.0]) echo(t);
The variable t is compared exactly with 1.0, and exact comparison is not
reliable for floating point values.
Basically, you should never use float inside a FOR loop, unless you add a
small value to make sure it stops where you want.
My suggestions for a reliable version of your loop is:
for (t=[0.0:0.05:1.0001]) echo(t);
or better, use integers:
for(i=[0:20]) { t=i*0.05;echo(t); }
In the first example, the extra .0001 reminds you that you are taking into
account the fact that floating numbers are approximate.
The second example is the best way, in my opinion, to loop trough a
sequence. Use an integer to count the steps, and derive all float values
from that integer.
If you want to make sure that your loop will always stop at 1.0 for any step
(s), then do this:
s=0.05; // step size
for (t=[0.0:s:1.0+s/2]) echo(t);
You are essentially adding 1/2 of one step to the end value, to make sure
you get that value.
I hope this helps!
--
View this message in context: http://forum.openscad.org/Loop-precision-floating-point-precision-tp14642p14643.html
Sent from the OpenSCAD mailing list archive at Nabble.com.
I do not recommend using a trick like
for (t=[0.0:0.05:1.0001])
to make a loop terminate.
0.05 can only be represented approximately as a binary floating point
number.
The error accumulates in each step of the loop.
This ever increasing error could affect the accuracy of your model,
depending on how the loop value is used.
It is better to iterate over integers, and use division to construct a
fraction
in each iteration of the loop.
On 19 November 2015 at 08:00, blobule roys@iro.umontreal.ca wrote:
Yes this is normal.
In your loop:
for (t=[0.0:0.05:1.0]) echo(t);
The variable t is compared exactly with 1.0, and exact comparison is not
reliable for floating point values.
Basically, you should never use float inside a FOR loop, unless you add a
small value to make sure it stops where you want.
My suggestions for a reliable version of your loop is:
for (t=[0.0:0.05:1.0001]) echo(t);
or better, use integers:
for(i=[0:20]) { t=i*0.05;echo(t); }
In the first example, the extra .0001 reminds you that you are taking into
account the fact that floating numbers are approximate.
The second example is the best way, in my opinion, to loop trough a
sequence. Use an integer to count the steps, and derive all float values
from that integer.
If you want to make sure that your loop will always stop at 1.0 for any
step
(s), then do this:
s=0.05; // step size
for (t=[0.0:s:1.0+s/2]) echo(t);
You are essentially adding 1/2 of one step to the end value, to make sure
you get that value.
I hope this helps!
--
View this message in context:
http://forum.openscad.org/Loop-precision-floating-point-precision-tp14642p14643.html
Sent from the OpenSCAD mailing list archive at Nabble.com.
OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Thanks all.
I change iterator to integer and add a 'let' function to calculate the
parameter by dividing.
a+
Vicnet
--
View this message in context: http://forum.openscad.org/Loop-precision-floating-point-precision-tp14642p14649.html
Sent from the OpenSCAD mailing list archive at Nabble.com.
With the most recent update, let() is no longer necessary in for() or other
flow control structure. You only need let() in list comprehension. (and
function definition?)
I still feel something is off... I get that IEEE double has finite
resolution, but failing to terminate a for loop correctly with a precision
of 1/25 that's OUCH.
--
View this message in context: http://forum.openscad.org/Loop-precision-floating-point-precision-tp14642p14650.html
Sent from the OpenSCAD mailing list archive at Nabble.com.
On 19 November 2015 at 09:46, ctchin c.t.chin@szu.edu.cn wrote:
With the most recent update, let() is no longer necessary in for() or other
flow control structure. You only need let() in list comprehension. (and
function definition?)
I still feel something is off... I get that IEEE double has finite
resolution, but failing to terminate a for loop correctly with a precision
of 1/25 that's OUCH.
read the loop: the run variable is compared with 1.0. if it only
arrives the tiniest fraction above the cutoff point, then 1 is never
reached.
(so 1.000000001 for instance). So it is not 1/25 but about 1/(2^52) =
1/4503599627370496 being off which makes the loop not terminate at
1.0.
--
View this message in context: http://forum.openscad.org/Loop-precision-floating-point-precision-tp14642p14650.html
Sent from the OpenSCAD mailing list archive at Nabble.com.
OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
ctchin:
0.05 cannot be represented exactly in binary floating point, regardless of
the precision. We happen to use 64 bit floats, but it doesn't matter how
many bits you have, it still can't be represented. We could use 1024 bit
floats, and the loop would still not terminate at 1. It's not a bug in
OpenSCAD, it is just how floating point works.
If we used decimal floating point, then 0.05 would have an exact
representation, but there's no hardware support for decimal floating point
on the platforms we support, so OpenSCAD would be a lot slower. Decimal
floating point also does not eliminate most of the weirdness associated
with floating point, it only addresses the problem of floating point
literals like 0.05 not having an exact representation.
The article "What Every Computer Scientist Should Know About Floating
Point" contains way more information than most OpenSCAD programmers would
probably care to know, but it's a classic reference and is good for anybody
who really wants to know the details about why float arithmetic is so
unintuitive, and how to write programs to compensate for the weirdness.
https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
The 'let' operator only works in expressions and in list comprehensions,
and is the only way to introduce local variable bindings in those contexts,
so your comment about 'let is no longer necessary' seems to be inaccurate.
Maybe you are thinking about the deprecation of the 'assign' operator.
On 19 November 2015 at 12:46, ctchin c.t.chin@szu.edu.cn wrote:
With the most recent update, let() is no longer necessary in for() or other
flow control structure. You only need let() in list comprehension. (and
function definition?)
I still feel something is off... I get that IEEE double has finite
resolution, but failing to terminate a for loop correctly with a precision
of 1/25 that's OUCH.
--
View this message in context:
http://forum.openscad.org/Loop-precision-floating-point-precision-tp14642p14650.html
Sent from the OpenSCAD mailing list archive at Nabble.com.
OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
On Nov 19, 2015, at 12:46 PM, ctchin c.t.chin@szu.edu.cn wrote:
still feel something is off... I get that IEEE double has finite
resolution, but failing to terminate a for loop correctly with a precision
of 1/25 that's OUCH.
Did I misunderstand something? I was under the impression that the loop indeed terminates, it’s just sometimes missing the last step since we use equality comparison.
In retrospect, we should perhaps have excluded the max range item from the range, but that’s a tough one to revert now due to the amount of existing designs using this.
-Marius
I've wished for an exclusive end value for a long time. Perhaps there could be some prefix to mark the value as exclusive? Something like "for(i = [0:2:!5])" maybe, though '!' probably isn't the best character to use.
You could also have an extra term, more like regex syntax, though you'd probably still want to use a special character to avoid collisions with variable names. Maybe just an extra trailing colon, like "for(i = [0:2:5:])"?
On Thursday, November 19, 2015 at 10:25, Marius Kintel wrote:
On Nov 19, 2015, at 12:46 PM, ctchin <c.t.chin@szu.edu.cn (mailto:c.t.chin@szu.edu.cn)> wrote:
still feel something is off... I get that IEEE double has finite
resolution, but failing to terminate a for loop correctly with a precision
of 1/25 that's OUCH.
Did I misunderstand something? I was under the impression that the loop indeed terminates, it’s just sometimes missing the last step since we use equality comparison.
In retrospect, we should perhaps have excluded the max range item from the range, but that’s a tough one to revert now due to the amount of existing designs using this.
-Marius
OpenSCAD mailing list
Discuss@lists.openscad.org (mailto:Discuss@lists.openscad.org)
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
vicnet wrote
Thanks all.
I change iterator to integer and add a 'let' function to calculate the
parameter by dividing.
a+
Vicnet
Check out this recent thread for why iterating over a floating point
increment is not reliable:
Simple addition of numbers introduces error
http://forum.openscad.org/Simple-addition-of-numbers-introduces-error-td14408.html
$ Runsun Pan, PhD
$ libs:
doctest ,
faces ( git ),
offline doc ( git ),
runscad.py( 1 , 2 , git );
$ tips:
hash( 1 , 2 ),
sweep ,
var( 1 , 2 ),
lerp ,
animGif ,
precision
--
View this message in context: http://forum.openscad.org/Loop-precision-floating-point-precision-tp14642p14655.html
Sent from the OpenSCAD mailing list archive at Nabble.com.