Discussion:
[ast-developers] [ast-users] Unit of least precision (ULP)/spacing between floating point number problems
Roland Mainz
2013-08-11 20:57:40 UTC
Permalink
On Sun, Aug 11, 2013 at 6:15 PM, Cedric Blancher
Here's one of my little tough problems which I am unable to solve
myself, even after looking at the source code of ast-ksh. The problem
below requires a good understanding how floating point numbers are
implemented in computers.
I'm trying to prototype code and like to iterate over a small, linear
area by using the C library function nextafter() to step forward the
smallest possible distance between each step, and print the number of
ksh -c 'float v ; integer iter ; for ((iter=0,v=4 ; v < 4.000000000001
&& iter < 10000000; v=nextafter(v,4.000000000001))) ; do
((iter++));done;print $iter '
2305843
The result 2305843 is correct.
However, if I use typeset -E (or just typeset) to declare the variable
v the loop runs forever, or in this case until it hits iter < 10000000
ksh -c 'typeset -E v ; integer iter ; for ((iter=0,v=4 ; v <
4.000000000001 && iter < 10000000; v=nextafter(v,4.000000000001))) ;
do ((iter++));done;print $iter '
10000000
Can anyone explain this?
float is an alias
this shows the alias definition
type float
which is
typeset -lE
this documents -l
typeset --?l
so for your example
typeset -E
gave you a double v and
typeset -lE
would give you a "long double" v
But why does nextafter() misbehave if I want to use a datatype smaller
than "long double"? Accuracy is a good thing, but in this case we
iterate too fine-grained, meaning the code should iterate over the
smallest possible steps of a double, but not over the smallest
possible steps of a long double.
Does anyone have a good idea how to fix this in ksh?
Grumpf... yes. Technically I feared that day may come when
|nextafter()| and |nexttoward()| were added in ksh93... ;-/

The issue is more or less like this: Both |nextafter(f|l|)\(\)| and
|nexttoward(f|l|)\(\)| step over the smallest possible quantity for
the specific { |float|, |double|, |long double| }-datatype and
therefore (for example) using |nextafterl()| (intended for |long
double|) for a |float| doesn't work because it does so small steps
that they cannot be represented in a |float| ... that causes the
endless loop in Tina's example.

The fix would be to "remember" the datatype (e.g. { |float|,
|double|, |long double| }) for a given variable and pass that down to
|arith_exec()| and call the specific version of |nextafter()| and
|nexttoward()| for that datatype, for example:
- variables declared via typeset -s -E/-X should use
|nextafterf()|/|nexttowardf()|
- variables declared via typeset -E/-X should use
|nextafter()|/|nexttoward()|
- variables declared via typeset -l -E/-X should use
|nextafterl()|/|nexttowardl()|
... if the platforms libc/libm do not have a matching
|nextafter(f|l|)\(\)|/|nexttoward(f|l|)\(\)| variant for the input
datatype then the "function not found"-error should be thrown.

Note that we do _not_ have to change the logic for all math
functions... AFAIK |nextafter()| and |nexttoward()| are the only
exceptions which require special handling...

Glenn: What do you think ?

----

Bye,
Roland
--
__ . . __
(o.\ \/ /.o) roland.mainz at nrubsig.org
\__\/\/__/ MPEG specialist, C&&JAVA&&Sun&&Unix programmer
/O /==\ O\ TEL +49 641 3992797
(;O/ \/ \O;)
Glenn Fowler
2013-08-12 16:36:46 UTC
Permalink
Post by Roland Mainz
On Sun, Aug 11, 2013 at 6:15 PM, Cedric Blancher
Here's one of my little tough problems which I am unable to solve
myself, even after looking at the source code of ast-ksh. The problem
below requires a good understanding how floating point numbers are
implemented in computers.
I'm trying to prototype code and like to iterate over a small, linear
area by using the C library function nextafter() to step forward the
smallest possible distance between each step, and print the number of
ksh -c 'float v ; integer iter ; for ((iter=0,v=4 ; v < 4.000000000001
&& iter < 10000000; v=nextafter(v,4.000000000001))) ; do
((iter++));done;print $iter '
2305843
The result 2305843 is correct.
However, if I use typeset -E (or just typeset) to declare the variable
v the loop runs forever, or in this case until it hits iter < 10000000
ksh -c 'typeset -E v ; integer iter ; for ((iter=0,v=4 ; v <
4.000000000001 && iter < 10000000; v=nextafter(v,4.000000000001))) ;
do ((iter++));done;print $iter '
10000000
Can anyone explain this?
float is an alias
this shows the alias definition
type float
which is
typeset -lE
this documents -l
typeset --?l
so for your example
typeset -E
gave you a double v and
typeset -lE
would give you a "long double" v
But why does nextafter() misbehave if I want to use a datatype smaller
than "long double"? Accuracy is a good thing, but in this case we
iterate too fine-grained, meaning the code should iterate over the
smallest possible steps of a double, but not over the smallest
possible steps of a long double.
Does anyone have a good idea how to fix this in ksh?
Grumpf... yes. Technically I feared that day may come when
|nextafter()| and |nexttoward()| were added in ksh93... ;-/
The issue is more or less like this: Both |nextafter(f|l|)\(\)| and
|nexttoward(f|l|)\(\)| step over the smallest possible quantity for
the specific { |float|, |double|, |long double| }-datatype and
therefore (for example) using |nextafterl()| (intended for |long
double|) for a |float| doesn't work because it does so small steps
that they cannot be represented in a |float| ... that causes the
endless loop in Tina's example.
The fix would be to "remember" the datatype (e.g. { |float|,
|double|, |long double| }) for a given variable and pass that down to
|arith_exec()| and call the specific version of |nextafter()| and
- variables declared via typeset -s -E/-X should use
|nextafterf()|/|nexttowardf()|
- variables declared via typeset -E/-X should use
|nextafter()|/|nexttoward()|
- variables declared via typeset -l -E/-X should use
|nextafterl()|/|nexttowardl()|
... if the platforms libc/libm do not have a matching
|nextafter(f|l|)\(\)|/|nexttoward(f|l|)\(\)| variant for the input
datatype then the "function not found"-error should be thrown.
this looks like the problem
Post by Roland Mainz
Note that we do _not_ have to change the logic for all math
functions... AFAIK |nextafter()| and |nexttoward()| are the only
exceptions which require special handling...
Glenn: What do you think ?
I'll meet with dgk shortly
ольга крыжановская
2013-08-12 16:43:41 UTC
Permalink
David send Roland a comment that nextafter(x+1.1,5) does not figure
the data type of x+1.1 correctly and always uses the data type of the
right value.

IMO the rules of ISO C (C1X) should apply.

The difficult part is that I do not know how to do that with the
arithmetic engine in ksh, some how the value of node.isfloat (which is
now a kind of enum describing which kind of floating point data type
is used - float, double, long double) must be recalculated based on
the left hand lhand_node.isfloat and right hand rhand_node.isfloat
value of such operations.

Olga
Post by Glenn Fowler
Post by Roland Mainz
On Sun, Aug 11, 2013 at 6:15 PM, Cedric Blancher
Here's one of my little tough problems which I am unable to solve
myself, even after looking at the source code of ast-ksh. The problem
below requires a good understanding how floating point numbers are
implemented in computers.
I'm trying to prototype code and like to iterate over a small, linear
area by using the C library function nextafter() to step forward the
smallest possible distance between each step, and print the number of
ksh -c 'float v ; integer iter ; for ((iter=0,v=4 ; v < 4.000000000001
&& iter < 10000000; v=nextafter(v,4.000000000001))) ; do
((iter++));done;print $iter '
2305843
The result 2305843 is correct.
However, if I use typeset -E (or just typeset) to declare the variable
v the loop runs forever, or in this case until it hits iter < 10000000
ksh -c 'typeset -E v ; integer iter ; for ((iter=0,v=4 ; v <
4.000000000001 && iter < 10000000; v=nextafter(v,4.000000000001))) ;
do ((iter++));done;print $iter '
10000000
Can anyone explain this?
float is an alias
this shows the alias definition
type float
which is
typeset -lE
this documents -l
typeset --?l
so for your example
typeset -E
gave you a double v and
typeset -lE
would give you a "long double" v
But why does nextafter() misbehave if I want to use a datatype smaller
than "long double"? Accuracy is a good thing, but in this case we
iterate too fine-grained, meaning the code should iterate over the
smallest possible steps of a double, but not over the smallest
possible steps of a long double.
Does anyone have a good idea how to fix this in ksh?
Grumpf... yes. Technically I feared that day may come when
|nextafter()| and |nexttoward()| were added in ksh93... ;-/
The issue is more or less like this: Both |nextafter(f|l|)\(\)| and
|nexttoward(f|l|)\(\)| step over the smallest possible quantity for
the specific { |float|, |double|, |long double| }-datatype and
therefore (for example) using |nextafterl()| (intended for |long
double|) for a |float| doesn't work because it does so small steps
that they cannot be represented in a |float| ... that causes the
endless loop in Tina's example.
The fix would be to "remember" the datatype (e.g. { |float|,
|double|, |long double| }) for a given variable and pass that down to
|arith_exec()| and call the specific version of |nextafter()| and
- variables declared via typeset -s -E/-X should use
|nextafterf()|/|nexttowardf()|
- variables declared via typeset -E/-X should use
|nextafter()|/|nexttoward()|
- variables declared via typeset -l -E/-X should use
|nextafterl()|/|nexttowardl()|
... if the platforms libc/libm do not have a matching
|nextafter(f|l|)\(\)|/|nexttoward(f|l|)\(\)| variant for the input
datatype then the "function not found"-error should be thrown.
this looks like the problem
Post by Roland Mainz
Note that we do _not_ have to change the logic for all math
functions... AFAIK |nextafter()| and |nexttoward()| are the only
exceptions which require special handling...
Glenn: What do you think ?
I'll meet with dgk shortly
_______________________________________________
ast-users mailing list
ast-users at lists.research.att.com
http://lists.research.att.com/mailman/listinfo/ast-users
--
, _ _ ,
{ \/`o;====- Olga Kryzhanovska -====;o`\/ }
.----'-/`-/ olga.kryzhanovska at gmail.com \-`\-'----.
`'-..-| / http://twitter.com/fleyta \ |-..-'`
/\/\ Solaris/BSD//C/C++ programmer /\/\
`--` `--`
David Korn
2013-08-13 02:16:23 UTC
Permalink
cc: ast-users at lists.research.att.com ast-developers at research.att.com
Subject: Re: Re: [ast-developers] [ast-users] Unit of least precision (ULP)/spacing between floating point number problems
--------
Post by ольга крыжановская
David send Roland a comment that nextafter(x+1.1,5) does not figure
the data type of x+1.1 correctly and always uses the data type of the
right value.
IMO the rules of ISO C (C1X) should apply.
The difficult part is that I do not know how to do that with the
arithmetic engine in ksh, some how the value of node.isfloat (which is
now a kind of enum describing which kind of floating point data type
is used - float, double, long double) must be recalculated based on
the left hand lhand_node.isfloat and right hand rhand_node.isfloat
value of such operations.
Olga
I hope to be able to do this correctly in a future release.

There are four types, integer, float, double, and long double.


David Korn
dgk at research.att.com
Wendy Lin
2013-08-13 02:28:20 UTC
Permalink
Post by David Korn
cc: ast-users at lists.research.att.com ast-developers at research.att.com
Subject: Re: Re: [ast-developers] [ast-users] Unit of least precision (ULP)/spacing between floating point number problems
--------
Post by ольга крыжановская
David send Roland a comment that nextafter(x+1.1,5) does not figure
the data type of x+1.1 correctly and always uses the data type of the
right value.
IMO the rules of ISO C (C1X) should apply.
The difficult part is that I do not know how to do that with the
arithmetic engine in ksh, some how the value of node.isfloat (which is
now a kind of enum describing which kind of floating point data type
is used - float, double, long double) must be recalculated based on
the left hand lhand_node.isfloat and right hand rhand_node.isfloat
value of such operations.
Olga
I hope to be able to do this correctly in a future release.
There are four types, integer, float, double, and long double.
Aren't there seven types, bool (0/1), short integer (typeset -s -i),
integer (typeset -i), long integer (typeset -li) and float (typeset -s
-E), double (typeset -E), and long double (typeset -l -E)?

Wendy
Wendy Lin
2013-08-13 02:28:20 UTC
Permalink
Post by David Korn
cc: ast-users at lists.research.att.com ast-developers at research.att.com
Subject: Re: Re: [ast-developers] [ast-users] Unit of least precision (ULP)/spacing between floating point number problems
--------
Post by ольга крыжановская
David send Roland a comment that nextafter(x+1.1,5) does not figure
the data type of x+1.1 correctly and always uses the data type of the
right value.
IMO the rules of ISO C (C1X) should apply.
The difficult part is that I do not know how to do that with the
arithmetic engine in ksh, some how the value of node.isfloat (which is
now a kind of enum describing which kind of floating point data type
is used - float, double, long double) must be recalculated based on
the left hand lhand_node.isfloat and right hand rhand_node.isfloat
value of such operations.
Olga
I hope to be able to do this correctly in a future release.
There are four types, integer, float, double, and long double.
Aren't there seven types, bool (0/1), short integer (typeset -s -i),
integer (typeset -i), long integer (typeset -li) and float (typeset -s
-E), double (typeset -E), and long double (typeset -l -E)?

Wendy
Tina Harriott
2013-09-04 16:41:24 UTC
Permalink
Post by David Korn
cc: ast-users at lists.research.att.com ast-developers at research.att.com
Subject: Re: Re: [ast-developers] [ast-users] Unit of least precision (ULP)/spacing between floating point number problems
--------
Post by ольга крыжановская
David send Roland a comment that nextafter(x+1.1,5) does not figure
the data type of x+1.1 correctly and always uses the data type of the
right value.
IMO the rules of ISO C (C1X) should apply.
The difficult part is that I do not know how to do that with the
arithmetic engine in ksh, some how the value of node.isfloat (which is
now a kind of enum describing which kind of floating point data type
is used - float, double, long double) must be recalculated based on
the left hand lhand_node.isfloat and right hand rhand_node.isfloat
value of such operations.
Olga
I hope to be able to do this correctly in a future release.
There are four types, integer, float, double, and long double.
How long will it take until ksh -c 'typeset -s -E x=4 ; print $((
x=nextafter(x,5) ))' uses nextafterf()?

Tina
--
Tina Harriott - Women in Mathematics
Contact: tina.harriott.math at gmail.com
Tina Harriott
2013-09-04 16:41:24 UTC
Permalink
Post by David Korn
cc: ast-users at lists.research.att.com ast-developers at research.att.com
Subject: Re: Re: [ast-developers] [ast-users] Unit of least precision (ULP)/spacing between floating point number problems
--------
Post by ольга крыжановская
David send Roland a comment that nextafter(x+1.1,5) does not figure
the data type of x+1.1 correctly and always uses the data type of the
right value.
IMO the rules of ISO C (C1X) should apply.
The difficult part is that I do not know how to do that with the
arithmetic engine in ksh, some how the value of node.isfloat (which is
now a kind of enum describing which kind of floating point data type
is used - float, double, long double) must be recalculated based on
the left hand lhand_node.isfloat and right hand rhand_node.isfloat
value of such operations.
Olga
I hope to be able to do this correctly in a future release.
There are four types, integer, float, double, and long double.
How long will it take until ksh -c 'typeset -s -E x=4 ; print $((
x=nextafter(x,5) ))' uses nextafterf()?

Tina
--
Tina Harriott - Women in Mathematics
Contact: tina.harriott.math at gmail.com
David Korn
2013-08-13 02:16:23 UTC
Permalink
cc: ast-users at lists.research.att.com ast-developers at research.att.com
Subject: Re: Re: [ast-developers] [ast-users] Unit of least precision (ULP)/spacing between floating point number problems
--------
Post by ольга крыжановская
David send Roland a comment that nextafter(x+1.1,5) does not figure
the data type of x+1.1 correctly and always uses the data type of the
right value.
IMO the rules of ISO C (C1X) should apply.
The difficult part is that I do not know how to do that with the
arithmetic engine in ksh, some how the value of node.isfloat (which is
now a kind of enum describing which kind of floating point data type
is used - float, double, long double) must be recalculated based on
the left hand lhand_node.isfloat and right hand rhand_node.isfloat
value of such operations.
Olga
I hope to be able to do this correctly in a future release.

There are four types, integer, float, double, and long double.


David Korn
dgk at research.att.com
David Korn
2013-08-13 12:33:22 UTC
Permalink
cc: ast-developers at lists.research.att.com ast-users at lists.research.att.com
Subject: Re: Re: [ast-users] [ast-developers] Unit of least precision (ULP)/spacing between floating point number problems
--------
Post by Wendy Lin
Aren't there seven types, bool (0/1), short integer (typeset -s -i),
integer (typeset -i), long integer (typeset -li) and float (typeset -s
-E), double (typeset -E), and long double (typeset -l -E)?
bool and short integer are currently the same as far as integer is
concerned.

Also, the math functions aren't affected by the size of an integer so
only the three float types and integer are relevant as far as
doing arithmetic in the shell.

David Korn
dgk at research.att.com
Roland Mainz
2013-09-19 04:37:12 UTC
Permalink
On Thu, Sep 19, 2013 at 3:28 AM, Tina Harriott
Here's one of my little tough problems which I am unable to solve
myself, even after looking at the source code of ast-ksh. The problem
below requires a good understanding how floating point numbers are
implemented in computers.
I'm trying to prototype code and like to iterate over a small, linear
area by using the C library function nextafter() to step forward the
smallest possible distance between each step, and print the number of
ksh -c 'float v ; integer iter ; for ((iter=0,v=4 ; v < 4.000000000001
&& iter < 10000000; v=nextafter(v,4.000000000001))) ; do
((iter++));done;print $iter '
2305843
The result 2305843 is correct.
However, if I use typeset -E (or just typeset) to declare the variable
v the loop runs forever, or in this case until it hits iter < 10000000
ksh -c 'typeset -E v ; integer iter ; for ((iter=0,v=4 ; v <
4.000000000001 && iter < 10000000; v=nextafter(v,4.000000000001))) ;
do ((iter++));done;print $iter '
10000000
Can anyone explain this?
float is an alias
this shows the alias definition
type float
which is
typeset -lE
this documents -l
typeset --?l
so for your example
typeset -E
gave you a double v and
typeset -lE
would give you a "long double" v
But why does nextafter() misbehave if I want to use a datatype smaller
than "long double"? Accuracy is a good thing, but in this case we
iterate too fine-grained, meaning the code should iterate over the
smallest possible steps of a double, but not over the smallest
possible steps of a long double.
typeset -E v ; integer iter
for ((iter=0,v=4 ; v < 4.000000000001 && iter < 10000000;
v=nextafter(v,4.000000000001))) ;do
((iter++))
done
print $iter
~/bin/ksh --version
version sh (AT&T Research) 93v- 2013-09-13
~/bin/ksh x.sh
10000000
Is it very hard to integrate the fix Mr. Mainz send? My professor is
asking for a solution (ksh, or switch to perl or python)
Erm... my patch wasn't exactly flawless...
AFAIK the issues are:
1. My patch only looked at the first argument to determinate the
datatype of the function needed and not both
2. Something like nextafter(x+1.1,5) causes issue because it raises
the question of the datatype of the result of |x+1.5|. If we ally the
C99 ruleset we get something like this:
x==|float|, then the datatype of |x+1.5| is |double|, because |1.5| is
a |double|
x==|double|, then the datatype of |x+1.5| is |double|, because both
|1.5| and |x| are |double|s
x==|long double|, then the datatype of |x+1.5| is |long double|,
because |x| is a |long double|

A solution to get [2] under control is to add type suffixes to
constants, e.g. |1.5F| is a |float|, |1.5| is a |double| and |1.5L| is
a |long double|.

A different way may be to bind the type of function to a variable, e.g. do this:
-- snip --
typeset -s -E v ; ... ; v.nextafter() # calls |nextafterf()| because v
is a |float|
typeset -E v ; ... ; v.nextafter() # calls |nextafter()| because v
is a |double|
typeset -l -E v ; ... ; v.nextafter() # calls |nextafterl()| because v
is a |long double|
-- snip --
... but that can only be done optionally because $((...))/((...))
arithmetic expressions should work like ISO C if possible...

----

Bye,
Roland
--
__ . . __
(o.\ \/ /.o) roland.mainz at nrubsig.org
\__\/\/__/ MPEG specialist, C&&JAVA&&Sun&&Unix programmer
/O /==\ O\ TEL +49 641 3992797
(;O/ \/ \O;)
Tina Harriott
2013-10-23 01:59:01 UTC
Permalink
Here's one of my little tough problems which I am unable to solve
myself, even after looking at the source code of ast-ksh. The problem
below requires a good understanding how floating point numbers are
implemented in computers.
I'm trying to prototype code and like to iterate over a small, linear
area by using the C library function nextafter() to step forward the
smallest possible distance between each step, and print the number of
ksh -c 'float v ; integer iter ; for ((iter=0,v=4 ; v < 4.000000000001
&& iter < 10000000; v=nextafter(v,4.000000000001))) ; do
((iter++));done;print $iter '
2305843
The result 2305843 is correct.
However, if I use typeset -E (or just typeset) to declare the variable
v the loop runs forever, or in this case until it hits iter < 10000000
ksh -c 'typeset -E v ; integer iter ; for ((iter=0,v=4 ; v <
4.000000000001 && iter < 10000000; v=nextafter(v,4.000000000001))) ;
do ((iter++));done;print $iter '
10000000
Can anyone explain this?
float is an alias
this shows the alias definition
type float
which is
typeset -lE
this documents -l
typeset --?l
so for your example
typeset -E
gave you a double v and
typeset -lE
would give you a "long double" v
But why does nextafter() misbehave if I want to use a datatype smaller
than "long double"? Accuracy is a good thing, but in this case we
iterate too fine-grained, meaning the code should iterate over the
smallest possible steps of a double, but not over the smallest
possible steps of a long double.
Tina
--
Tina Harriott - Women in Mathematics
Contact: tina.harriott.math at gmail.com
I am still running into this bug in ksh 20131010. Does it still take
long to have it fixed?

Tina
--
Tina Harriott - Women in Mathematics
Contact: tina.harriott.math at gmail.com
Tina Harriott
2013-11-18 22:43:43 UTC
Permalink
Post by Tina Harriott
Here's one of my little tough problems which I am unable to solve
myself, even after looking at the source code of ast-ksh. The problem
below requires a good understanding how floating point numbers are
implemented in computers.
I'm trying to prototype code and like to iterate over a small, linear
area by using the C library function nextafter() to step forward the
smallest possible distance between each step, and print the number of
ksh -c 'float v ; integer iter ; for ((iter=0,v=4 ; v < 4.000000000001
&& iter < 10000000; v=nextafter(v,4.000000000001))) ; do
((iter++));done;print $iter '
2305843
The result 2305843 is correct.
However, if I use typeset -E (or just typeset) to declare the variable
v the loop runs forever, or in this case until it hits iter < 10000000
ksh -c 'typeset -E v ; integer iter ; for ((iter=0,v=4 ; v <
4.000000000001 && iter < 10000000; v=nextafter(v,4.000000000001))) ;
do ((iter++));done;print $iter '
10000000
Can anyone explain this?
float is an alias
this shows the alias definition
type float
which is
typeset -lE
this documents -l
typeset --?l
so for your example
typeset -E
gave you a double v and
typeset -lE
would give you a "long double" v
But why does nextafter() misbehave if I want to use a datatype smaller
than "long double"? Accuracy is a good thing, but in this case we
iterate too fine-grained, meaning the code should iterate over the
smallest possible steps of a double, but not over the smallest
possible steps of a long double.
Tina
--
Tina Harriott - Women in Mathematics
Contact: tina.harriott.math at gmail.com
I am still running into this bug in ksh 20131010. Does it still take
long to have it fixed?
Is this going to be fixed in the next alpha?

Tina
--
Tina Harriott - Women in Mathematics
Contact: tina.harriott.math at gmail.com
Loading...