On 12/17/2016 04:36 PM, Johan Jonker wrote:
It is the question if it's a bug.
Maybe it is more important to understand it.
No, it's not a bug. It's an issue inherent to how
floating point numbers work in computers. I guess
the only way to get unlimited precision is if you
allow unlimited memory and unlimited computing
power.
The specific problem with catching the end condition
of the for loop might be possible to solve using
some tricks mentioned here in the forum not long
ago. But this is a specific workaround and will
not solve the "never compare floating point values
for being equal" problem in general.
ciao,
Torsten.
OpenSCAD has always worked this way, and this bug is reported multiple
times a year. Last time it was reported on the forum was Nov 21, "For loops
not making sense??".
I have fixed this bug in my version of OpenSCAD, and I've described the
proposed bug fix in issue #1592.
My fix is controversial. This is because there are two mental models for
understanding ranges like [first:step:last].
1
1.2
1.4
1.6
1.8
2
2.2
2.4000000000000004
2.6
2.8
3
(By contrast, OpenSCAD stops at 2.8.)
My implementation accounts for floating point imprecision: the 'last' value
might be an approximation of the final value. So [1 : 0.2 : 2.99] and [1 :
0.2 : 3.01] produce the same result as [1 : 0.2 : 3].
With my design, if you just assume that the 'last' value is the final value
in the range, and write your code as if that is true, then you'll always
get what you expect, and any small floating point inaccuracy in your code
will be compensated for.
My implementation is a bit more complicated than this, because it
compensates for floating point inaccuracy. The 'last' value is considered
to be an approximation to the final value in the range. The actual final
value is computed as
first + round((last-first)/step) * step
Also, I use multiplication to compute each intermediate value, instead of
repeated addition, to avoid the accumulation of small errors.
If you are the type of person who prefers to think about ranges in terms of
the underlying implementation, then you may not like my implementation,
because it is more complicated.
I personally believe that it is better for the behaviour of ranges to have
a simple high level model that makes sense to beginners, who don't know the
underlying implementation. It's simple to explain that 'last' is the final
value in the range, and it's more complicated to explain the underlying
implementation, and to explain why [1:0.2:3] ends at 2.8.
Doug Moen.
On 17 December 2016 at 02:59, Johan Jonker johangjonker@zonnet.nl wrote:
I found a remarkable difference in version 2016.10.4 using for statement
with increments smaller than 1. Sometimes the end value is not reached.
for (a7=[ 6.8:1/5:7.8]) echo(A7=a7);
for (a=[ 7.2:1/5:8.2]) echo(A=a);
Output is
ECHO: A7 = 6.8
ECHO: A7 = 7
ECHO: A7 = 7.2
ECHO: A7 = 7.4
ECHO: A7 = 7.6
ECHO: A = 7.2
ECHO: A = 7.4
ECHO: A = 7.6
ECHO: A = 7.8
ECHO: A = 8
ECHO: A = 8.2
--
View this message in context: http://forum.openscad.org/for-
statement-doesn-t-do-all-the-steps-sometimes-tp19591.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
The only thing I don't like about your suggestion Doug, is that the user
doesn't have the ability to state the epsilon to use. That is prolly good
for some, but not so good for others.
--
View this message in context: http://forum.openscad.org/for-statement-doesn-t-do-all-the-steps-sometimes-tp19591p19608.html
Sent from the OpenSCAD mailing list archive at Nabble.com.
Doug,
Given your statement:
"I personally believe that it is better for the behaviour of ranges to
have a simple high level model that makes sense to beginners, who don't
know the underlying implementation. It's simple to explain that 'last' is
the final value in the range, and it's more complicated to explain the
underlying implementation, and to explain why [1:0.2:3] ends at 2.8."
If you look at the actual documentation on OpenSCAD.
end - stop when next value would be past end
I personally believe the first part of your statement is how the
documentation says its supposed to work. That is my opinion, however.
Jerry
For loop
Evaluate each value in a range or vector, applying it to the following
Action.
for(variable = [start : increment : end])
for(variable = [start : end])
for(variable = [vector])
parameters
As a range [ start : <increment : > end ] (see section on range
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/General#Ranges)Note:
For range, values are separated by colons rather than commas used in
vectors.*start - initial valueincrement* or step - amount to increase
the value, optional, default = 1**end - stop when next value would be
past end
--
Extra Ham Operator: K7AZJ
Registered Linux User: 275424
Raspberry Pi and Openscad developer
The most exciting phrase to hear in science - the one that heralds new
discoveries - is not "Eureka!" but "That's funny...".- Isaac. Asimov
On Sat, Dec 17, 2016 at 11:02 AM, adrian adrianh.bsc@gmail.com wrote:
The only thing I don't like about your suggestion Doug, is that the user
doesn't have the ability to state the epsilon to use. That is prolly good
for some, but not so good for others.
--
View this message in context: http://forum.openscad.org/for-
statement-doesn-t-do-all-the-steps-sometimes-tp19591p19608.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
Adrian said "The only thing I don't like about your suggestion Doug, is
that the user
doesn't have the ability to state the epsilon to use."
I would vote no to epsilons.
Right now, [a:step:b] is a closed range that includes both a and b, most of
the time.
But it's unreliable, and sometimes b is omitted, and it becomes a half-open
range.
This is a bug, and to work around the bug, you add an epsilon to b.
For example, Johan worked around the bug like this:
[ 6.8 : 1/5 : 7.8 + 0.000001]
where 0.000001 is an explicit epsilon value.
In order to understand why an epsilon is sometimes needed, and what value
to use
as epsilon, you have to know the internal implementation details.
The goal of my bug fix is to eliminate the need for epsilons, and to
eliminate the
need to understand internal implementation details. [x:step:y] is always a
closed
range that includes both x and y. It works reliably, not just "most of the
time".
If we introduced a syntax like [first:step:last:epsilon], then what would
that even
mean? Is it a closed range, a half open range, what is it? I assume that the
meaning would be complex and would require a full understanding of the
implementation, which is what I'm trying to avoid.
I will also note that no other programming language has a range syntax that
includes an epsilon specification.
On 17 December 2016 at 13:02, adrian adrianh.bsc@gmail.com wrote:
The only thing I don't like about your suggestion Doug, is that the user
doesn't have the ability to state the epsilon to use. That is prolly good
for some, but not so good for others.
--
View this message in context: http://forum.openscad.org/for-
statement-doesn-t-do-all-the-steps-sometimes-tp19591p19608.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
Forum users and developers,
First let me state that you have done a great job with OpenSCAD.
But this unending complaint about real number indices for loop has nothing
to do with design intent.
This is why we should not let computer scientist define the specs
of a program.
It is too bad that software writers try to be too smart, and try to get
away with the limitations of our computing machines as Karsten stated it
very clearly.
By design, any loop mechanism should have the index being INTEGER ONLY.
Then the parameters that matters would be computed inside the loop,
so rounding errors due to the implementation would be minimized.
But remember, most of the user are not computer scientists, they are
people trying to do 3D modeling with a tool given to them for free.
The best way to avoid major criticism would be to allow only integer
indices, and provide an error if they are not.
When I started as a young engineer, the tools of choice were pencil, paper and
a slide rule.
So I learned very fast that many decimals are not important, what is important
is just a few significant decimals (3 significant digit with a slide rule), but
the order of magnitude has to be right.
This drove me to understand that calculators are more of a nuisance than a help
in mechanical design which is what we should worry about.
So please, get rid of real numbers in loop index, and just document it.
You will see the amount of complaints decrease very fast.
Just my two cents.
On Dec 17, 2016, at 4:09 PM, r.d. terramir terramircomputers@gmail.com wrote:
It is really proper use of floating point math, nothing OpenSCAD specific.
I always use integer indices and compute everything from those. I think it has been mentioned before that OpenSCAD could do that internally. I.e. instead of repeatedly adding it could have a hidden counter that it multiples the step value by.
echo(6.8 + 5 * 0.2 - 7.8);
ECHO: 0
That would give more accurate results but there would still be caveats.
On 17 December 2016 at 15:36, Johan Jonker johangjonker@zonnet.nl wrote:
It is the question if it's a bug.
Maybe it is more important to understand it.
I tried to do the same in VBA.
There the same thing happens.
I more like a warning in the on line manual about the proper use of the
statement.
--
View this message in context: http://forum.openscad.org/for-statement-doesn-t-do-all-the-steps-sometimes-tp19591p19603.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
OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Doug,
again a vote for silent behavior and hidden magic - and no means to roll
back. You propose a solution that will potentially break existing code and
algorithms. The semantical difference can be a "hard to spot" problem as
soon as nested loops come into play and can affect each (!) nesting level.
Look at this double loop, (where only the inner loop is effected, as the
outer loop is classical):
first = 6.8;
step = .2;
last = 8;
for (y=[7.4:.05:8.4]) loops(y);
module loops(last)
{
echo(classic = classic_loop(first, step, last));
echo(dougs = doug_loop(first, step, last));
echo();
}
function classic_loop(first, step, last) = [for(x = [first: step: last])
x];
function doug_loop(first, step, last) =
let(first_ = 0)
let(step_ = sign(step))
let(last_ = round((last-first)/step))
[for(i = [first_: step_: last_]) first+i*step];
this is the output:
ECHO: classic = [6.8, 7, 7.2, 7.4]
ECHO: dougs = [6.8, 7, 7.2, 7.4]
ECHO:
ECHO: classic = [6.8, 7, 7.2, 7.4]
ECHO: dougs = [6.8, 7, 7.2, 7.4]
ECHO:
ECHO: classic = [6.8, 7, 7.2, 7.4]
ECHO: dougs = [6.8, 7, 7.2, 7.4, 7.6]
ECHO:
ECHO: classic = [6.8, 7, 7.2, 7.4]
ECHO: dougs = [6.8, 7, 7.2, 7.4, 7.6]
ECHO:
ECHO: classic = [6.8, 7, 7.2, 7.4]
ECHO: dougs = [6.8, 7, 7.2, 7.4, 7.6]
ECHO:
ECHO: classic = [6.8, 7, 7.2, 7.4, 7.6]
ECHO: dougs = [6.8, 7, 7.2, 7.4, 7.6]
ECHO:
ECHO: classic = [6.8, 7, 7.2, 7.4, 7.6]
ECHO: dougs = [6.8, 7, 7.2, 7.4, 7.6]
ECHO:
ECHO: classic = [6.8, 7, 7.2, 7.4, 7.6]
ECHO: dougs = [6.8, 7, 7.2, 7.4, 7.6, 7.8]
ECHO:
ECHO: classic = [6.8, 7, 7.2, 7.4, 7.6]
ECHO: dougs = [6.8, 7, 7.2, 7.4, 7.6, 7.8]
ECHO:
ECHO: classic = [6.8, 7, 7.2, 7.4, 7.6, 7.8]
ECHO: dougs = [6.8, 7, 7.2, 7.4, 7.6, 7.8]
ECHO:
ECHO: classic = [6.8, 7, 7.2, 7.4, 7.6, 7.8]
ECHO: dougs = [6.8, 7, 7.2, 7.4, 7.6, 7.8]
ECHO:
ECHO: classic = [6.8, 7, 7.2, 7.4, 7.6, 7.8]
ECHO: dougs = [6.8, 7, 7.2, 7.4, 7.6, 7.8, 8]
ECHO:
ECHO: classic = [6.8, 7, 7.2, 7.4, 7.6, 7.8]
ECHO: dougs = [6.8, 7, 7.2, 7.4, 7.6, 7.8, 8]
ECHO:
ECHO: classic = [6.8, 7, 7.2, 7.4, 7.6, 7.8, 8]
ECHO: dougs = [6.8, 7, 7.2, 7.4, 7.6, 7.8, 8]
ECHO:
ECHO: classic = [6.8, 7, 7.2, 7.4, 7.6, 7.8, 8]
ECHO: dougs = [6.8, 7, 7.2, 7.4, 7.6, 7.8, 8]
ECHO:
ECHO: classic = [6.8, 7, 7.2, 7.4, 7.6, 7.8, 8]
ECHO: dougs = [6.8, 7, 7.2, 7.4, 7.6, 7.8, 8, 8.2]
ECHO:
ECHO: classic = [6.8, 7, 7.2, 7.4, 7.6, 7.8, 8, 8.2]
ECHO: dougs = [6.8, 7, 7.2, 7.4, 7.6, 7.8, 8, 8.2]
ECHO:
ECHO: classic = [6.8, 7, 7.2, 7.4, 7.6, 7.8, 8, 8.2]
ECHO: dougs = [6.8, 7, 7.2, 7.4, 7.6, 7.8, 8, 8.2]
ECHO:
ECHO: classic = [6.8, 7, 7.2, 7.4, 7.6, 7.8, 8, 8.2]
ECHO: dougs = [6.8, 7, 7.2, 7.4, 7.6, 7.8, 8, 8.2, 8.4]
ECHO:
ECHO: classic = [6.8, 7, 7.2, 7.4, 7.6, 7.8, 8, 8.2]
ECHO: dougs = [6.8, 7, 7.2, 7.4, 7.6, 7.8, 8, 8.2, 8.4]
ECHO:
--
View this message in context: http://forum.openscad.org/for-statement-doesn-t-do-all-the-steps-sometimes-tp19591p19622.html
Sent from the OpenSCAD mailing list archive at Nabble.com.
Interesting to read the discussion and solutions, thanks for that
Speaking for myself:
I assume that the for loop is originally made to be used to count a specific
number of steps like in- for (i = [1:100])
On the other hand I do not always like the no-functional names i or count
and prefer an functional named variable, like this:
function circle(r) = [ for (angle [0:360]) [rsin(angle), rcos(angle)]];
The problem is that I want to have a while statement that performs
increaments until a limit value is reached.
And sometimes these limits values are floating point values.
-for- loops can be used to behave like that but you need to understand how
they behave with floating point values. I encountered the behaviour while
debugging a 3D design. The same limits exist in other programming languages
but I never encountered it there.
I now use this solution in the cross-section of my saxophone mouthpiece
design where beta an alfa are dynamic transitions in the cross-section (they
are visible in the figure):
for (angle= [each [beta:(180-2beta)/45:180-beta+0.1],
each [180-beta:(beta-alfa)/45:180-alfa+0.1],
each [180-alfa:(180+2alfa)/45:360+alfa+0.1],
each [360+alfa: (beta-alfa)/45:360+beta-0.1]])
http://forum.openscad.org/file/n19623/mp.jpg
--
View this message in context: http://forum.openscad.org/for-statement-doesn-t-do-all-the-steps-sometimes-tp19591p19623.html
Sent from the OpenSCAD mailing list archive at Nabble.com.
On Sat, Dec 17, 2016 at 11:16:40AM -0500, doug moen wrote:
My implementation accounts for floating point imprecision: the 'last' value
might be an approximation of the final value. So [1 : 0.2 : 2.99] and [1 :
0.2 : 3.01] produce the same result as [1 : 0.2 : 3].
Auch! I know that steps of 0.2 are "inaccurate" and "compensation for
floating point inaccuracies may be necessary". But if I want N steps
where the step size is never smaller than 0.01, and I do NOT want to
include the final object at index "3", I'll write:
[1:3/N:2.99] to make sure that the final one will NOT be rendered.
Fixing the "assumption" that 3/N is never < 0.01, I'll write:
[1:3/N:3-1/N], again to make sure that I don't include the final
one at (floating point accuracy equal to) 3.
This is important if, say I'm building a fence:
N=4;
eps=0.1;
for (i=[0:1/N:3-eps]) translate ([i,0,0]) cube ([0.1,0.1,1]);
for (i=[0:1/N:1-eps]) translate ([3,i,0]) cube ([0.1,0.1,1]);
for (i=[4:1/N:5-eps]) translate ([i,1,0]) cube ([0.1,0.1,1]);
The final values each time are meant NOT to be included each time,
otherwise I get a double post at those points.
Roger.
--
** R.E.Wolff@BitWizard.nl ** http://www.BitWizard.nl/ ** +31-15-2600998 **
** Delftechpark 26 2628 XH Delft, The Netherlands. KVK: 27239233 **
-- BitWizard writes Linux device drivers for any device you may have! --
The plan was simple, like my brother-in-law Phil. But unlike
Phil, this plan just might work.
The fix I implemented is based on the Haskell implementation of floating
point numeric ranges. That was the best reference implementation that I
could find at the time.
The first:step:last syntax is taken from Matlab. I found Matlab source code
for the colon operator, it's here:
https://gist.github.com/Juanlu001/7383894
This fixes the bug, and it is more backward compatible with OpenSCAD than
the Haskell implementation.
On 17 December 2016 at 02:59, Johan Jonker johangjonker@zonnet.nl wrote:
I found a remarkable difference in version 2016.10.4 using for statement
with increments smaller than 1. Sometimes the end value is not reached.
for (a7=[ 6.8:1/5:7.8]) echo(A7=a7);
for (a=[ 7.2:1/5:8.2]) echo(A=a);
Output is
ECHO: A7 = 6.8
ECHO: A7 = 7
ECHO: A7 = 7.2
ECHO: A7 = 7.4
ECHO: A7 = 7.6
ECHO: A = 7.2
ECHO: A = 7.4
ECHO: A = 7.6
ECHO: A = 7.8
ECHO: A = 8
ECHO: A = 8.2
--
View this message in context: http://forum.openscad.org/for-
statement-doesn-t-do-all-the-steps-sometimes-tp19591.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