SKILL : should the order matter for the plus function

  • Thread starter Suresh Jeevanandam
  • Start date
S

Suresh Jeevanandam

Guest
After debugging my code for an hour, I found that the sum of a list of
numbers can be *different* based on the order in SKILL !!!

When I enter,
(-22m + 2m + 2m + 2m + 2m + 14m )
=> 6.938894e-18

(-22m + 2m + 2m + 2m + 2m + 14m ) == 0.0
=> nil

(2m + 2m + 2m + 2m + 14m - 22m )
=> 0.0

(2m + 2m + 2m + 2m + 14m - 22m ) == 0.0
=> t

Any Idea how to get 0.0 irrespective of the order.

Regards,
Suresh
 
Suresh Jeevanandam <sureshj@DELETETHISti.com> writes:

After debugging my code for an hour, I found that the sum of a list
of numbers can be *different* based on the order in SKILL !!!
That's an expected effect of using floating point numbers.

Probably the most cited paper introducing the subject:

http://citeseer.ist.psu.edu/goldberg91what.html

(You can download the paper using the links at upper right).

Any Idea how to get 0.0 irrespective of the order.
Don't use floating point numbers.

Yours,

--
Jean-Marc
 
A simple solution I found is to replace all the lines
from
lhs == 0.0
to
abs(lhs) < 1n

( If 1n is negligible in the comparison ).

Regards,
Suresh


Jean-Marc Bourguet wrote:
Suresh Jeevanandam <sureshj@DELETETHISti.com> writes:


After debugging my code for an hour, I found that the sum of a list
of numbers can be *different* based on the order in SKILL !!!


That's an expected effect of using floating point numbers.

Probably the most cited paper introducing the subject:

http://citeseer.ist.psu.edu/goldberg91what.html

(You can download the paper using the links at upper right).


Any Idea how to get 0.0 irrespective of the order.


Don't use floating point numbers.

Yours,
 
In article <d06ci6$51b$1@home.itg.ti.com> Suresh Jeevanandam <sureshj@DELETETHISti.com> writes:
After debugging my code for an hour, I found that the sum of a list of
numbers can be *different* based on the order in SKILL !!!

When I enter,
(-22m + 2m + 2m + 2m + 2m + 14m )
=> 6.938894e-18

(-22m + 2m + 2m + 2m + 2m + 14m ) == 0.0
=> nil

(2m + 2m + 2m + 2m + 14m - 22m )
=> 0.0

(2m + 2m + 2m + 2m + 14m - 22m ) == 0.0
=> t

Any Idea how to get 0.0 irrespective of the order.
With floating point you cannot.

When doing floating point compares, you should always do "fuzzy" compares.
Figure out your desired accuracy and compare within that.

For example:

MyDeviation = 1.0e-6
MyResult = <calculation>
MyComparator = 0.0
if( abs(MyResult - MyComparator) < MyDeviation
then
;equal within MyDeviation range of accuracy
t
else
;not equal within MyDeviation range of accuracy
nil
)

Note that this is standard practice when dealing with floating point, since
floating point is by definition not totally accurate.

-Pete Zakel
(phz@seeheader.nospam)

"Most turkeys taste better the day after; my mother's tasted better the day
before."
-Rita Rudner
 
Hi suresh, what would you like the equal function to
do if you pass it strings, or other data types?

equal("abc" "ABC" 1n)
equal("plus(1 2)" "3" 0.0)
equal('(1 2 3) '(1.0 2.00000001 3) 1m)

?

Suresh Jeevanandam wrote:
Instead, the standard cadence functions to compare can take an
additional optional argument 'accuracy'.
so that we get

equal(plus(-22m 8m 14m) 0.0)
=> nil

equal(plus(-22m 8m 14m) 0.0 1n) ; This is the proposed way, the third
argument is the optional accuracy.
=> t

I think this should be more efficient, any comments..

Regards,
Suresh

Jim Newton wrote:

Hi Pete, i think you'll find the same results if you rewrite
your program in C, Perl, Java, Python, Fortran or almost
any language. What would you like the language to do
with the round off error? 2/1000 is not epxressable
exactly with a finite number of decimal places in binary.

The only way to assure that you get zero when you calculate
this is to handle the round off yourself; don't leave it
up to the language. For example, you can choose a grid
say grid=1.0/1000 and you do not care how that is
represented in binary.

Then before applying the + operator, round all the numbers
to the nearest grid, then after adding up, round the
result to the nearest grid.


(procedure (add_numbers_on_grid n_grid l_numbers)
;; first express the numbers in terms of the given grid
l_numbers = (foreach mapcar num l_numbers
(round num / n_grid))
;; then add up the integers and multiply by grid
n_grid * (apply 'plus l_numbers))

I think you'll find that the function add_numbers_on_grid
will add up your numbers in any order the same way.

Note that (apply 'plus l_numbers) will add up a list of number
but only works for lists of length 2 or more. The function
will not work for adding up zero or 1 numbers.

(add_numbers_on_grid l_numbers 1m '( -22m 2m 2m 2m 2m 14m)) ==> 0.0

(add_numbers_on_grid l_numbers 1m '( 2m 2m 2m 2m 14m -22m)) ==> 0.0


Hope this helps.
-jim
 
The optional argument should be ignored because its meaningless :)

Regards,
Suresh
Jim Newton wrote:
Hi suresh, what would you like the equal function to
do if you pass it strings, or other data types?

equal("abc" "ABC" 1n)
equal("plus(1 2)" "3" 0.0)
equal('(1 2 3) '(1.0 2.00000001 3) 1m)

?
 
Andrew Beckett wrote:
On Mon, 07 Mar 2005 10:29:20 +0530, Suresh Jeevanandam
sureshj@DELETETHISti.com> wrote:


Instead, the standard cadence functions to compare can take an
additional optional argument 'accuracy'.
so that we get

equal(plus(-22m 8m 14m) 0.0)
=> nil

equal(plus(-22m 8m 14m) 0.0 1n) ; This is the proposed way, the third
argument is the optional accuracy.
=> t

I think this should be more efficient, any comments..

Regards,
Suresh



Other languages don't have this - why not simply write a function yourself to
do this?

Different applications will have different ideas on how equal something should
be. Personally I would probably use a relative tolerance together with a
smaller absolute tolerance). That allows you to cope with numbers very close
to zero, without running out of headroom.

But for some applications that would be overkill - a simple absolute tolerance
would be sufficient.

(a note on terminology here - a relative tolerance would be some fraction of
the numbers involved in the comparison; an absolute tolerance is a fixed
number).

Andrew.

Other languages are used by professional hackers and they may have
custom library to do these kind of common jobs.
But SKILL is used by people whose main job is not programming. Most of
the people would tend to use the == operator with the floating point
values too.
I think almost everybody would have to compare floating point numbers in
their scripts at some point of time. If all the people need to write the
same function why not implement it as part of the language itself.
If there are multiple solutions lets identify those most common stuffs
and implement only those.
In almost 90% of the cases either absolute or relative tolerance would
be fine.

Also, in most of the other languages only operators are available. In
skill we have both == operator and the equivalent function.

We can make either absolute tolerance or relative tolerance or both as
the standard functions. ( In the third case we would require an
additional optional boolean argument to indicate absolute/relative
tolerance)

Lets put atleast one of these into the standard function. Let the user
write his own function any other way of dealing this problem.)


Regards,
Suresh
 
order does not seem to matter to much:

x=1.0
while(not(equal( 1.0 plus(1.0 x)))
x=x/10
)
x

x=1.0
while(not(equal( plus(1.0 x) 1.0 ))
x=x/10
)
x

x=1.0
while(not(equal( plus(x 1.0) 1.0 ))
x=x/10
)
x

x=1.0
while(not(equal( 1.0 plus(x 1.0) ))
x=x/10
)
x

Gives me always 0.1femto (on an ultrasparc box with ic5033 , 32bit)

Suresh Jeevanandam wrote:
After debugging my code for an hour, I found that the sum of a list of
numbers can be *different* based on the order in SKILL !!!

When I enter,
(-22m + 2m + 2m + 2m + 2m + 14m )
=> 6.938894e-18

(-22m + 2m + 2m + 2m + 2m + 14m ) == 0.0
=> nil

(2m + 2m + 2m + 2m + 14m - 22m )
=> 0.0

(2m + 2m + 2m + 2m + 14m - 22m ) == 0.0
=> t

Any Idea how to get 0.0 irrespective of the order.

Regards,
Suresh
 
Hi Pete, i think you'll find the same results if you rewrite
your program in C, Perl, Java, Python, Fortran or almost
any language. What would you like the language to do
with the round off error? 2/1000 is not epxressable
exactly with a finite number of decimal places in binary.

The only way to assure that you get zero when you calculate
this is to handle the round off yourself; don't leave it
up to the language. For example, you can choose a grid
say grid=1.0/1000 and you do not care how that is
represented in binary.

Then before applying the + operator, round all the numbers
to the nearest grid, then after adding up, round the
result to the nearest grid.


(procedure (add_numbers_on_grid n_grid l_numbers)
;; first express the numbers in terms of the given grid
l_numbers = (foreach mapcar num l_numbers
(round num / n_grid))
;; then add up the integers and multiply by grid
n_grid * (apply 'plus l_numbers))

I think you'll find that the function add_numbers_on_grid
will add up your numbers in any order the same way.

Note that (apply 'plus l_numbers) will add up a list of number
but only works for lists of length 2 or more. The function
will not work for adding up zero or 1 numbers.

(add_numbers_on_grid l_numbers 1m '( -22m 2m 2m 2m 2m 14m)) ==> 0.0

(add_numbers_on_grid l_numbers 1m '( 2m 2m 2m 2m 14m -22m)) ==> 0.0


Hope this helps.
-jim

Pete nospam Zakel wrote:
In article <d06ci6$51b$1@home.itg.ti.com> Suresh Jeevanandam <sureshj@DELETETHISti.com> writes:

After debugging my code for an hour, I found that the sum of a list of
numbers can be *different* based on the order in SKILL !!!

When I enter,
(-22m + 2m + 2m + 2m + 2m + 14m )
=> 6.938894e-18

(-22m + 2m + 2m + 2m + 2m + 14m ) == 0.0
=> nil

(2m + 2m + 2m + 2m + 14m - 22m )
=> 0.0

(2m + 2m + 2m + 2m + 14m - 22m ) == 0.0
=> t

Any Idea how to get 0.0 irrespective of the order.


With floating point you cannot.

When doing floating point compares, you should always do "fuzzy" compares.
Figure out your desired accuracy and compare within that.

For example:

MyDeviation = 1.0e-6
MyResult = <calculation
MyComparator = 0.0
if( abs(MyResult - MyComparator) < MyDeviation
then
;equal within MyDeviation range of accuracy
t
else
;not equal within MyDeviation range of accuracy
nil
)

Note that this is standard practice when dealing with floating point, since
floating point is by definition not totally accurate.

-Pete Zakel
(phz@seeheader.nospam)

"Most turkeys taste better the day after; my mother's tasted better the day
before."
-Rita Rudner
 
Instead, the standard cadence functions to compare can take an
additional optional argument 'accuracy'.
so that we get

equal(plus(-22m 8m 14m) 0.0)
=> nil

equal(plus(-22m 8m 14m) 0.0 1n) ; This is the proposed way, the third
argument is the optional accuracy.
=> t

I think this should be more efficient, any comments..

Regards,
Suresh

Jim Newton wrote:
Hi Pete, i think you'll find the same results if you rewrite
your program in C, Perl, Java, Python, Fortran or almost
any language. What would you like the language to do
with the round off error? 2/1000 is not epxressable
exactly with a finite number of decimal places in binary.

The only way to assure that you get zero when you calculate
this is to handle the round off yourself; don't leave it
up to the language. For example, you can choose a grid
say grid=1.0/1000 and you do not care how that is
represented in binary.

Then before applying the + operator, round all the numbers
to the nearest grid, then after adding up, round the
result to the nearest grid.


(procedure (add_numbers_on_grid n_grid l_numbers)
;; first express the numbers in terms of the given grid
l_numbers = (foreach mapcar num l_numbers
(round num / n_grid))
;; then add up the integers and multiply by grid
n_grid * (apply 'plus l_numbers))

I think you'll find that the function add_numbers_on_grid
will add up your numbers in any order the same way.

Note that (apply 'plus l_numbers) will add up a list of number
but only works for lists of length 2 or more. The function
will not work for adding up zero or 1 numbers.

(add_numbers_on_grid l_numbers 1m '( -22m 2m 2m 2m 2m 14m)) ==> 0.0

(add_numbers_on_grid l_numbers 1m '( 2m 2m 2m 2m 14m -22m)) ==> 0.0


Hope this helps.
-jim
 
On Mon, 07 Mar 2005 10:29:20 +0530, Suresh Jeevanandam
<sureshj@DELETETHISti.com> wrote:

Instead, the standard cadence functions to compare can take an
additional optional argument 'accuracy'.
so that we get

equal(plus(-22m 8m 14m) 0.0)
=> nil

equal(plus(-22m 8m 14m) 0.0 1n) ; This is the proposed way, the third
argument is the optional accuracy.
=> t

I think this should be more efficient, any comments..

Regards,
Suresh
Other languages don't have this - why not simply write a function yourself to
do this?

Different applications will have different ideas on how equal something should
be. Personally I would probably use a relative tolerance together with a
smaller absolute tolerance). That allows you to cope with numbers very close
to zero, without running out of headroom.

But for some applications that would be overkill - a simple absolute tolerance
would be sufficient.

(a note on terminology here - a relative tolerance would be some fraction of
the numbers involved in the comparison; an absolute tolerance is a fixed
number).

Andrew.
 

Welcome to EDABoard.com

Sponsor

Back
Top