Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

rounding problem ?

49 views
Skip to first unread message

Luc Moulinier

unread,
Jan 19, 2012, 8:18:41 AM1/19/12
to
Dear All,

It seems there are some rounding problems when making simple maths...
And tht leads to bad results ! Is there someone to explain me what is
happening here ?

set Llim -99999999999.
set v -2.0
while {$v <= 2.} {
lappend Llim $v $v
set v [expr {$v + 0.1}]
}
lappend Llim 99999999999.

Output:
-99999999999. -2.
-2. -1.9
-1.9 -1.7999999999999998
-1.7999999999999998 -1.6999999999999997
-1.6999999999999997 -1.5999999999999996
-1.5999999999999996 -1.4999999999999996
-1.4999999999999996 -1.3999999999999995
..........
..........
1.7000000000000013 1.8000000000000014
1.8000000000000014 1.9000000000000015
1.9000000000000015 99999999999.

I miss the 1.9 2. couple.

ActiveTcl 8.6b1.2
Linux kilida 2.6.32-32-generic #62-Ubuntu SMP Wed Apr 20 21:52:38 UTC
2011 x86_64 GNU/Linux

Luc

Georgios Petasis

unread,
Jan 19, 2012, 8:53:25 AM1/19/12
to
The same happens also under windows.
Although the man page says never change the value of tcl_precision,
setting: set tcl_precision 15
seems to "hide" the problem.

George

Don Porter

unread,
Jan 19, 2012, 9:08:45 AM1/19/12
to
Luc Moulinier wrote:
> set Llim -99999999999.
> set v -2.0
> while {$v <= 2.} {
> lappend Llim $v $v
> set v [expr {$v + 0.1}]
> }
> lappend Llim 99999999999.
>
> Output:
> -99999999999. -2.
> -2. -1.9
> -1.9 -1.7999999999999998
> -1.7999999999999998 -1.6999999999999997
> -1.6999999999999997 -1.5999999999999996
> -1.5999999999999996 -1.4999999999999996
> -1.4999999999999996 -1.3999999999999995
> ..........
> ..........
> 1.7000000000000013 1.8000000000000014
> 1.8000000000000014 1.9000000000000015
> 1.9000000000000015 99999999999.
>
> I miss the 1.9 2. couple.

Continuing in an interactive tclsh...

% set v
2.0000000000000013
% expr {$v <= 2.}
0

So by the conditions you set for the loop, that value should not
go onto the list.

Your real question is "Why can't I get exactly correct results when
I repeatedly add the value 0.1? Why am I getting these rounding
errors?"

The reason is that computers do their figuring in base 2, and there's
no number of bits that can represent the value 0.1 exactly. Contrast
with the values 0.5, 0.25, 0.125, which you can demand exact
representation. This means roundoff issues are unavoidable, and you
must write code that's aware of that. Testing for equality of
floating point values as a condition to take a branch or end a loop
is usually the wrong thing to do because of this.

Two broad alternatives to dealing with this. First, relax the equality
test to something looser [if {$v < 2.+$epsilon} ...] where $epsilon
is chosen suitable to the needs of your problem. Second, do your
counting and looping in the domain of integers, which are exactly
represented.

set v -20
while {$v <= 20} {
set val [expr {$v*0.1}]
lappend Llim $val
incr v
}

These issues are encountered very early when learning to do numeric
computing. I'm surprised you're not already familiar with them.

--
| Don Porter Applied and Computational Mathematics Division |
| donald...@nist.gov Information Technology Laboratory |
| http://math.nist.gov/~DPorter/ NIST |
|______________________________________________________________________|

Luc Moulinier

unread,
Jan 19, 2012, 9:17:43 AM1/19/12
to
Interestingly, with
set tcl_precision 15 the result becomes

-99999999999. -2.0
-2.0 -1.9
-1.9 -1.8
......
-1.3 -1.2
-1.2 -1.1
-1.1 -0.999999999999999
-0.999999999999999 -0.899999999999999
-0.899999999999999 -0.799999999999999
-0.799999999999999 -0.699999999999999
-0.699999999999999 -0.599999999999999
-0.599999999999999 -0.499999999999999
-0.499999999999999 -0.399999999999999
-0.399999999999999 -0.299999999999999
-0.299999999999999 -0.199999999999999
-0.199999999999999 -0.0999999999999994
-0.0999999999999994 6.38378239159465e-16
6.38378239159465e-16 0.100000000000001
0.100000000000001 0.200000000000001
0.200000000000001 0.300000000000001
0.300000000000001 0.400000000000001
0.400000000000001 0.500000000000001
0.500000000000001 0.600000000000001
0.600000000000001 0.700000000000001
0.700000000000001 0.800000000000001
0.800000000000001 0.900000000000001
0.900000000000001 1.0
1.0 1.1
1.1 1.2
.....
1.7 1.8
1.8 1.9
1.9 99999999999.

Note :
- the 6.38378239159465e-16 instead of 0.0
- the 2. value is still missing, So 1.9+0.1 is still more than 2.

What should we do ?

Luc

Georgios Petasis

unread,
Jan 19, 2012, 9:46:09 AM1/19/12
to
All these are correct, but we are within a high-level language:

a) The machine epsilon is not really accessible from tcl,
b) the man page for tclvars has some interesting statements:

"tcl_precision
This variable controls the number of digits to generate when
converting floating-point values to strings. It defaults to 0.
Applications should not change this value; it is provided for
compatibility with legacy code.

The default value of 0 is special, meaning that Tcl should convert
numbers using as few digits as possible while still distinguishing any
floating point number from its nearest neighbours. It differs from using
an arbitrarily high value for tcl_precision in that an inexact number
like 1.4 will convert as 1.4 rather than 1.3999999999999999 even though
the latter is nearer to the exact value of the binary number."

This suggests something different to what learned early at numeric
computing, and not all users may be aware of what "conversion" is and
when Tcl "converts".

George

Arjen Markus

unread,
Jan 19, 2012, 9:57:45 AM1/19/12
to
> George- Tekst uit oorspronkelijk bericht niet weergeven -
>
> - Tekst uit oorspronkelijk bericht weergeven -

The machine epsilon is available via one of the packages in Tcllib's
math module (I forget the precise name).

And while it is true that Tcl is a high-level language, somewhere deep
down it still must obey the laws of the bits it is built on. An
alternative is to use decimal arithmetic, but that tends to be
slower than binary arithmetic (because of the mismatch at a low
level).

Perhaps the arbitrary-precision package, again in Tcllib's math
module,
may help. With that you can define the precision you want and it is
built on integer arithmetic, rather than floating-point. But you pay
a price ...

Regards,

Arjen

Don Porter

unread,
Jan 19, 2012, 10:05:43 AM1/19/12
to
Georgios Petasis wrote:
> All these are correct, but we are within a high-level language:
>
> a) The machine epsilon is not really accessible from tcl,

I was not referring to the machine epsilon.

> b) the man page for tclvars has some interesting statements:
>
> "tcl_precision

"tcl_precision" was a blunder that we've thankfully shoved into
legacy status. Do not reanimate the zombie.

Any non-default value of "tcl_precision" (*) breaks EIAS, and is
therefore at odds with the fundamentals of reasoning about Tcl values.

% set tcl_precision 12
12
% set pi [expr {4*atan(1)}]
3.14159265359
% expr {$pi == 3.14159265359}
0

(*) ok, ok, the value "17" is probably ok for all existing systems.

Luc Moulinier

unread,
Jan 19, 2012, 10:28:32 AM1/19/12
to
Hello Don,

Thanks for the reply and the little course. It's really clear, and I
feel less stupid ! (not really hard in fact ... ;-) )
You wrote :
"These issues are encountered very early when learning to do numeric
computing. I'm surprised you're not already familiar with them. "

The reason is that ... I'm a structural biologist, that went to
bioinformatics. So I don't have a strong background in computing
science. During my studies, we did some programming in Fortran, that's
all !
My knowledge in Tcl/Tk,C and OpenGL are all hands-on learning.

And a more general note. We are in fact quite a lot of people in my
case, practicing programming without being a computer scientist.
That's also one of the reason people use Tcl/Tk, as it has been made
to be easily learned. So don't blame us not to be experts in computer
scince ! We're learning ! ;-)

Luc

Emiliano

unread,
Jan 19, 2012, 12:39:55 PM1/19/12
to
On 19 ene, 12:28, Luc Moulinier <luc.moulin...@igbmc.fr> wrote:

Note that this is not a Tcl problem/limitation, but a floating point
one.
Python people has a document on this issue which mostly applies to Tcl
(or
any other language which uses IEEE-754 floating point arithmetic)

http://docs.python.org/tutorial/floatingpoint.html

On my machine:

emiliano@beaujolais:~$ tclsh8.6
% expr 0.1 + 0.2 - 0.3
5.551115123125783e-17
emiliano@beaujolais:~$ python2.6
>>> 0.1 + 0.2 - 0.3
5.5511151231257827e-17

Regards
Emiliano

Joe English

unread,
Jan 19, 2012, 2:21:35 PM1/19/12
to
Luc Moulinier wrote:
>
> It seems there are some rounding problems when making simple maths...
> And tht leads to bad results ! Is there someone to explain me what is
> happening here ?
[ slightly edited, -HE ]
> set v -2.0
> while {$v <= 2.} {
> set v [expr {$v + 0.1}]
> }


To better understand what's going on, get pencil and paper
and try the following arithmetic exercise:

The fraction 1/7 in decimal is 0.142857...
Now add up seven copies:

0.142857
+ 0.142857
+ 0.142857
+ 0.142857
+ 0.142857
+ 0.142857
+ 0.142857
----------
= 0.999999

Hm, we've got some roundoff error there.
Try it with more significant digits:

0.142857143
+ 0.142857143
+ 0.142857143
+ 0.142857143
+ 0.142857143
+ 0.142857143
+ 0.142857143
-------------
= 1.000000001


Floating point arithmetic in computers works the same way,
except that the computer uses base 2 instead of base 10.
And in base 2, the fraction 1/10 (== 0.1 in decimal) has
an infinitely repeating expansion, just like 1/7 does
in decimal.

Does that make things any clearer?


--JE

Luc Moulinier

unread,
Jan 20, 2012, 3:27:09 AM1/20/12
to
Many thanks to all of you !

this seems to be background knowledge in computer science I was not
aware of. It's good to learn !
If any of you have some needs in structural biology ... ;-)

Thanks again !
luc

Arjen Markus

unread,
Jan 20, 2012, 4:23:00 AM1/20/12
to
Well ... I do not know if it is structural biology, but I do want
to know a bit more about certain aspects of toxicology and
microbiology.
(Not kidding, but this is really off-topic ;))

Regards,

Arjen
0 new messages