discuss@lists.openscad.org

OpenSCAD general discussion Mailing-list

View all threads

Simple addition of numbers introduces error

R
runsun
Thu, Nov 12, 2015 5:35 PM

Just encountered an odd thing. The process is simple: add 0.1 and 0.02, to
see if it equals 0.12.

echo( 1/10 == 0.1 );  // true
echo( 2/100 == 0.02 ); // true
echo( 1/10 + 2/100 == 0.12 ); // false <===== duhh ???

How come 1/10 and 2/100 both are accurate, but not if they are added ?

It seems that a simple operation of addition introduces error:

echo( (1/10 + 2/100 - 0.12)*pow(10,10) ) ==> 1.38778e-07

I tried several other numbers but only 0.12 goes wrong.

This means that if you have code like:

a = some_value;
b = some_other_value;
c = value a + b;

A boolean check like c==a+b? would give false negative some time but not all
the time, which would be extremely hard to debug.


$  Runsun Pan, PhD

$ libs: doctest , faces ( git ), offline doc ( git ),runscad.py( 1 , 2 , git );

$ tips: hash( 1 , 2 ), sweep , var , lerp , animGif

--
View this message in context: http://forum.openscad.org/Simple-addition-of-numbers-introduces-error-tp14408.html
Sent from the OpenSCAD mailing list archive at Nabble.com.

Just encountered an odd thing. The process is simple: add 0.1 and 0.02, to see if it equals 0.12. > echo( 1/10 == 0.1 ); // true > echo( 2/100 == 0.02 ); // true > echo( 1/10 + 2/100 == 0.12 ); // false <===== duhh ??? How come 1/10 and 2/100 both are accurate, but not if they are added ? It seems that a simple operation of addition introduces error: > echo( (1/10 + 2/100 - 0.12)*pow(10,10) ) ==> 1.38778e-07 I tried several other numbers but only 0.12 goes wrong. This means that if you have code like: > a = some_value; > b = some_other_value; > c = value a + b; A boolean check like c==a+b? would give false negative some time but not all the time, which would be extremely hard to debug. ----- $ Runsun Pan, PhD $ libs: doctest , faces ( git ), offline doc ( git ),runscad.py( 1 , 2 , git ); $ tips: hash( 1 , 2 ), sweep , var , lerp , animGif -- View this message in context: http://forum.openscad.org/Simple-addition-of-numbers-introduces-error-tp14408.html Sent from the OpenSCAD mailing list archive at Nabble.com.
YA
Yona Appletree
Thu, Nov 12, 2015 6:12 PM

Runsun,

This is due to the inherent nature of floating point numbers. Not all
values can be represented exactly, and this behavior is quite standard.
It's generally not advised to do equality checks on floats... you should
always use a range check.

This does basically the same thing in javascript:

node

.1 + .02

0.12000000000000001

.1 + .02 == .12

false

  • Yona

runsun mailto:runsun@gmail.com
November 12, 2015 at 09:35
Just encountered an odd thing. The process is simple: add 0.1 and 0.02, to
see if it equals 0.12.

echo( 1/10 == 0.1 );  // true
echo( 2/100 == 0.02 ); // true
echo( 1/10 + 2/100 == 0.12 ); // false<===== duhh ???

How come 1/10 and 2/100 both are accurate, but not if they are added ?

It seems that a simple operation of addition introduces error:

echo( (1/10 + 2/100 - 0.12)*pow(10,10) ) ==>  1.38778e-07

I tried several other numbers but only 0.12 goes wrong.

This means that if you have code like:

a = some_value;
b = some_other_value;
c = value a + b;

A boolean check like c==a+b? would give false negative some time but not all
the time, which would be extremely hard to debug.


$  Runsun Pan, PhD

$ libs: doctest , faces ( git ), offline doc ( git ),runscad.py( 1 , 2 , git );

$ tips: hash( 1 , 2 ), sweep , var , lerp , animGif

--
View this message in context: http://forum.openscad.org/Simple-addition-of-numbers-introduces-error-tp14408.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

Runsun, This is due to the inherent nature of floating point numbers. Not all values can be represented exactly, and this behavior is quite standard. It's generally not advised to do equality checks on floats... you should always use a range check. This does basically the same thing in javascript: # node > .1 + .02 0.12000000000000001 > .1 + .02 == .12 false - Yona > runsun <mailto:runsun@gmail.com> > November 12, 2015 at 09:35 > Just encountered an odd thing. The process is simple: add 0.1 and 0.02, to > see if it equals 0.12. > >> echo( 1/10 == 0.1 ); // true >> echo( 2/100 == 0.02 ); // true >> echo( 1/10 + 2/100 == 0.12 ); // false<===== duhh ??? > > How come 1/10 and 2/100 both are accurate, but not if they are added ? > > It seems that a simple operation of addition introduces error: > >> echo( (1/10 + 2/100 - 0.12)*pow(10,10) ) ==> 1.38778e-07 > > I tried several other numbers but only 0.12 goes wrong. > > This means that if you have code like: > >> a = some_value; >> b = some_other_value; >> c = value a + b; > > A boolean check like c==a+b? would give false negative some time but not all > the time, which would be extremely hard to debug. > > > > > ----- > > $ Runsun Pan, PhD > > $ libs: doctest , faces ( git ), offline doc ( git ),runscad.py( 1 , 2 , git ); > > $ tips: hash( 1 , 2 ), sweep , var , lerp , animGif > > > > > > > -- > View this message in context: http://forum.openscad.org/Simple-addition-of-numbers-introduces-error-tp14408.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
R
runsun
Thu, Nov 12, 2015 6:27 PM

Thx Hypher. Good to know.

I have a unit test lib in which comparing two values is essential, so
floating point comparison is unavoidable. Guess I'll have to resolve it in
some other way.


$  Runsun Pan, PhD

$ libs: doctest , faces ( git ), offline doc ( git ),runscad.py( 1 , 2 , git );

$ tips: hash( 1 , 2 ), sweep , var , lerp , animGif

--
View this message in context: http://forum.openscad.org/Simple-addition-of-numbers-introduces-error-tp14408p14411.html
Sent from the OpenSCAD mailing list archive at Nabble.com.

Thx Hypher. Good to know. I have a unit test lib in which comparing two values is essential, so floating point comparison is unavoidable. Guess I'll have to resolve it in some other way. ----- $ Runsun Pan, PhD $ libs: doctest , faces ( git ), offline doc ( git ),runscad.py( 1 , 2 , git ); $ tips: hash( 1 , 2 ), sweep , var , lerp , animGif -- View this message in context: http://forum.openscad.org/Simple-addition-of-numbers-introduces-error-tp14408p14411.html Sent from the OpenSCAD mailing list archive at Nabble.com.
AC
Alan Cox
Thu, Nov 12, 2015 6:42 PM

On Thu, 12 Nov 2015 11:27:22 -0700 (MST)
runsun runsun@gmail.com wrote:

Thx Hypher. Good to know.

I have a unit test lib in which comparing two values is essential, so
floating point comparison is unavoidable. Guess I'll have to resolve it in
some other way.

The usual approach would be

abs(a - b) < ACCEPTABLE_ERROR

Whether adding an ~= operator to OpenSCAD would be helpful I don't know.
It's difficult to define "approximately" in a way that works for every
use.

Alan

On Thu, 12 Nov 2015 11:27:22 -0700 (MST) runsun <runsun@gmail.com> wrote: > Thx Hypher. Good to know. > > I have a unit test lib in which comparing two values is essential, so > floating point comparison is unavoidable. Guess I'll have to resolve it in > some other way. The usual approach would be abs(a - b) < ACCEPTABLE_ERROR Whether adding an ~= operator to OpenSCAD would be helpful I don't know. It's difficult to define "approximately" in a way that works for every use. Alan
RW
Rob Ward
Thu, Nov 12, 2015 9:07 PM

On 13/11/15 05:42, Alan Cox wrote:

On Thu, 12 Nov 2015 11:27:22 -0700 (MST)
runsun runsun@gmail.com wrote:

Thx Hypher. Good to know.

I have a unit test lib in which comparing two values is essential, so
floating point comparison is unavoidable. Guess I'll have to resolve it in
some other way.

The usual approach would be

abs(a - b) < ACCEPTABLE_ERROR

Whether adding an ~= operator to OpenSCAD would be helpful I don't know.
It's difficult to define "approximately" in a way that works for every
use.

Alan


OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

Could there be a setting like the $fn=20; to control 'smoothness', and
have it set the level of 'approximation',
therefore the feature is available and "let the user beware"?

$fa=0.001; //floating point resolved to within 0.001%

If this was localised to within modules, it could be turned off and on
as required??

Rob

On 13/11/15 05:42, Alan Cox wrote: > On Thu, 12 Nov 2015 11:27:22 -0700 (MST) > runsun <runsun@gmail.com> wrote: > >> Thx Hypher. Good to know. >> >> I have a unit test lib in which comparing two values is essential, so >> floating point comparison is unavoidable. Guess I'll have to resolve it in >> some other way. > The usual approach would be > > abs(a - b) < ACCEPTABLE_ERROR > > Whether adding an ~= operator to OpenSCAD would be helpful I don't know. > It's difficult to define "approximately" in a way that works for every > use. > > Alan > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org > Could there be a setting like the $fn=20; to control 'smoothness', and have it set the level of 'approximation', therefore the feature is available and "let the user beware"? $fa=0.001; //floating point resolved to within 0.001% If this was localised to within modules, it could be turned off and on as required?? Rob
RW
Rob Ward
Thu, Nov 12, 2015 9:19 PM

On 13/11/15 04:35, runsun wrote:

Just encountered an odd thing. The process is simple: add 0.1 and 0.02, to
see if it equals 0.12.

echo( 1/10 == 0.1 );  // true
echo( 2/100 == 0.02 ); // true
echo( 1/10 + 2/100 == 0.12 ); // false <===== duhh ???

How come 1/10 and 2/100 both are accurate, but not if they are added ?

It seems that a simple operation of addition introduces error:

echo( (1/10 + 2/100 - 0.12)*pow(10,10) ) ==> 1.38778e-07

I tried several other numbers but only 0.12 goes wrong.

This means that if you have code like:

a = some_value;
b = some_other_value;
c = value a + b;

A boolean check like c==a+b? would give false negative some time but not all
the time, which would be extremely hard to debug.


$  Runsun Pan, PhD

$ libs: doctest , faces ( git ), offline doc ( git ),runscad.py( 1 , 2 , git );

$ tips: hash( 1 , 2 ), sweep , var , lerp , animGif

--
View this message in context: http://forum.openscad.org/Simple-addition-of-numbers-introduces-error-tp14408.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

echo( (1/10 + 2/100) ==0.12); // also reports false???
echo( (1/10 + 2/100)) //produces 0.12, curious and curious-er!!

Rob

On 13/11/15 04:35, runsun wrote: > Just encountered an odd thing. The process is simple: add 0.1 and 0.02, to > see if it equals 0.12. > >> echo( 1/10 == 0.1 ); // true >> echo( 2/100 == 0.02 ); // true >> echo( 1/10 + 2/100 == 0.12 ); // false <===== duhh ??? > How come 1/10 and 2/100 both are accurate, but not if they are added ? > > It seems that a simple operation of addition introduces error: > >> echo( (1/10 + 2/100 - 0.12)*pow(10,10) ) ==> 1.38778e-07 > I tried several other numbers but only 0.12 goes wrong. > > This means that if you have code like: > >> a = some_value; >> b = some_other_value; >> c = value a + b; > A boolean check like c==a+b? would give false negative some time but not all > the time, which would be extremely hard to debug. > > > > > ----- > > $ Runsun Pan, PhD > > $ libs: doctest , faces ( git ), offline doc ( git ),runscad.py( 1 , 2 , git ); > > $ tips: hash( 1 , 2 ), sweep , var , lerp , animGif > > > > > > > -- > View this message in context: http://forum.openscad.org/Simple-addition-of-numbers-introduces-error-tp14408.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 > echo( (1/10 + 2/100) ==0.12); // also reports false??? echo( (1/10 + 2/100)) //produces 0.12, curious and curious-er!! Rob
NH
nop head
Thu, Nov 12, 2015 9:45 PM

0.1 and 0.02 are infinitely recurring numbers in binary so that is why they
are never equal in finite word length arithmetic. In general a lot more
fractions are not exact in binary.
echo() does some rounding, which is why it gives 0.12.

Perhaps runsun could convert to strings with str to compare them. E.g.

x = 0.1 + 0.02;

echo(x == 0.12);
echo(str(x) == "0.12");

ECHO: false

ECHO: true

On 12 November 2015 at 21:19, Rob Ward rl.ward@bigpond.com wrote:

On 13/11/15 04:35, runsun wrote:

Just encountered an odd thing. The process is simple: add 0.1 and 0.02, to
see if it equals 0.12.

echo( 1/10 == 0.1 );  // true

echo( 2/100 == 0.02 ); // true
echo( 1/10 + 2/100 == 0.12 ); // false <===== duhh ???

How come 1/10 and 2/100 both are accurate, but not if they are added ?

It seems that a simple operation of addition introduces error:

echo( (1/10 + 2/100 - 0.12)*pow(10,10) ) ==> 1.38778e-07

I tried several other numbers but only 0.12 goes wrong.

This means that if you have code like:

a = some_value;

b = some_other_value;
c = value a + b;

A boolean check like c==a+b? would give false negative some time but not
all
the time, which would be extremely hard to debug.


$  Runsun Pan, PhD

$ libs: doctest , faces ( git ), offline doc ( git ),runscad.py( 1 , 2 ,
git );

$ tips: hash( 1 , 2 ), sweep , var , lerp , animGif

--
View this message in context:
http://forum.openscad.org/Simple-addition-of-numbers-introduces-error-tp14408.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

echo( (1/10 + 2/100) ==0.12); // also reports false???

echo( (1/10 + 2/100)) //produces 0.12, curious and curious-er!!

Rob


OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

0.1 and 0.02 are infinitely recurring numbers in binary so that is why they are never equal in finite word length arithmetic. In general a lot more fractions are not exact in binary. echo() does some rounding, which is why it gives 0.12. Perhaps runsun could convert to strings with str to compare them. E.g. x = 0.1 + 0.02; echo(x == 0.12); echo(str(x) == "0.12"); ECHO: false ECHO: true On 12 November 2015 at 21:19, Rob Ward <rl.ward@bigpond.com> wrote: > On 13/11/15 04:35, runsun wrote: > >> Just encountered an odd thing. The process is simple: add 0.1 and 0.02, to >> see if it equals 0.12. >> >> echo( 1/10 == 0.1 ); // true >>> echo( 2/100 == 0.02 ); // true >>> echo( 1/10 + 2/100 == 0.12 ); // false <===== duhh ??? >>> >> How come 1/10 and 2/100 both are accurate, but not if they are added ? >> >> It seems that a simple operation of addition introduces error: >> >> echo( (1/10 + 2/100 - 0.12)*pow(10,10) ) ==> 1.38778e-07 >>> >> I tried several other numbers but only 0.12 goes wrong. >> >> This means that if you have code like: >> >> a = some_value; >>> b = some_other_value; >>> c = value a + b; >>> >> A boolean check like c==a+b? would give false negative some time but not >> all >> the time, which would be extremely hard to debug. >> >> >> >> >> ----- >> >> $ Runsun Pan, PhD >> >> $ libs: doctest , faces ( git ), offline doc ( git ),runscad.py( 1 , 2 , >> git ); >> >> $ tips: hash( 1 , 2 ), sweep , var , lerp , animGif >> >> >> >> >> >> >> -- >> View this message in context: >> http://forum.openscad.org/Simple-addition-of-numbers-introduces-error-tp14408.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 >> >> echo( (1/10 + 2/100) ==0.12); // also reports false??? > echo( (1/10 + 2/100)) //produces 0.12, curious and curious-er!! > > > Rob > > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >
C
ctchin
Fri, Nov 13, 2015 2:37 AM

I encounter this im a very real world way when replicating an object.  I was
making a
ring of LED's and was shocked when I can't reliably make an integer number
of LED
around a circle.

Digging, I created this demo call nasty.scad :

The lesson is that you have to be very careful and deliberate setting the
end value of for() loops.

--
View this message in context: http://forum.openscad.org/Simple-addition-of-numbers-introduces-error-tp14408p14430.html
Sent from the OpenSCAD mailing list archive at Nabble.com.

I encounter this im a very real world way when replicating an object. I was making a ring of LED's and was shocked when I can't reliably make an integer number of LED around a circle. Digging, I created this demo call nasty.scad : The lesson is that you have to be very careful and deliberate setting the end value of for() loops. -- View this message in context: http://forum.openscad.org/Simple-addition-of-numbers-introduces-error-tp14408p14430.html Sent from the OpenSCAD mailing list archive at Nabble.com.
R
runsun
Fri, Nov 13, 2015 10:44 PM

Alan Cox wrote

The usual approach would be

abs(a - b) < ACCEPTABLE_ERROR

nophead wrote

Perhaps runsun could convert to strings with str to compare them. E.g.

x = 0.1 + 0.02;

echo(x == 0.12);
echo(str(x) == "0.12");

ECHO: false
ECHO: true

Thx to Alan and nophead. Both approaches are in fact used in my doctest lib
already. It's just that after months of success, something tickling (or
breaking) my brain cells, let me start suspecting that it is not quite right
yet.

I now see that Openscad uses 17 significant digits for the internal
operations, and 6 digits for display. I'll have to think about if my lib
needs to change based on this findings.


$  Runsun Pan, PhD

$ libs: doctest , faces ( git ), offline doc ( git ),runscad.py( 1 , 2 , git );

$ tips: hash( 1 , 2 ), sweep , var , lerp , animGif

--
View this message in context: http://forum.openscad.org/Simple-addition-of-numbers-introduces-error-tp14408p14464.html
Sent from the OpenSCAD mailing list archive at Nabble.com.

Alan Cox wrote > The usual approach would be > > abs(a - b) < ACCEPTABLE_ERROR nophead wrote > Perhaps runsun could convert to strings with str to compare them. E.g. > > x = 0.1 + 0.02; > > echo(x == 0.12); > echo(str(x) == "0.12"); > > ECHO: false > ECHO: true Thx to Alan and nophead. Both approaches are in fact used in my doctest lib already. It's just that after months of success, something tickling (or breaking) my brain cells, let me start suspecting that it is not quite right yet. I now see that Openscad uses 17 significant digits for the internal operations, and 6 digits for display. I'll have to think about if my lib needs to change based on this findings. ----- $ Runsun Pan, PhD $ libs: doctest , faces ( git ), offline doc ( git ),runscad.py( 1 , 2 , git ); $ tips: hash( 1 , 2 ), sweep , var , lerp , animGif -- View this message in context: http://forum.openscad.org/Simple-addition-of-numbers-introduces-error-tp14408p14464.html Sent from the OpenSCAD mailing list archive at Nabble.com.
R
runsun
Fri, Nov 13, 2015 10:49 PM

@ ctchin,

Thx. Your nasty.scad helps to show that it's better not use a fraction as
the step in a for=[beg:step:end] manner. Good to know.


$  Runsun Pan, PhD

$ libs: doctest , faces ( git ), offline doc ( git ),runscad.py( 1 , 2 , git );

$ tips: hash( 1 , 2 ), sweep , var , lerp , animGif

--
View this message in context: http://forum.openscad.org/Simple-addition-of-numbers-introduces-error-tp14408p14465.html
Sent from the OpenSCAD mailing list archive at Nabble.com.

@ ctchin, Thx. Your nasty.scad helps to show that it's better not use a fraction as the step in a for=[beg:step:end] manner. Good to know. ----- $ Runsun Pan, PhD $ libs: doctest , faces ( git ), offline doc ( git ),runscad.py( 1 , 2 , git ); $ tips: hash( 1 , 2 ), sweep , var , lerp , animGif -- View this message in context: http://forum.openscad.org/Simple-addition-of-numbers-introduces-error-tp14408p14465.html Sent from the OpenSCAD mailing list archive at Nabble.com.