Cedric Blancher wrote:
>
> Why do we need typeset -X? Can someone explain the difference between
> typeset -X and the existing typeset -E float format?
The difference is the ASCII representation. If you declare a variable
using typeset -E varname/typeset -F varname the ASCII representation
will use the base10. Since the internal floating-point representation
for a |long double| (e.g. IEEE754) uses base2 you get
base2--->base10--->base2 conversion/rounding errors if you convert a
variable to a string and back multiple times. ISO C99 solved this
problem by defining a new ASCII representation which uses a hexadecimal
notation for floating-point values which allows 100% accurate conversion
from the internal memory format into an ASCII string and back into the
machine's internal representation.
Example for the hexfloat format:
-- snip --
$ ksh93 -c 'float x=64.1 ; printf "%e\n%f\n%g\n%a\n" x x x
x'
6.410000e+01
64.100000
64.1
0x1.0066666666666666666666666666p+06
-- snip --
... e.g. "0x1.0066666666666666666666666666p+06" is the C99 hexadecimal
representation of the base10 value "64.1".
Example for hitting a rounding error:
-- snip --
alias hexfloat="typeset -lX"
set -o errexit
float x
hexfloat y
float res
typeset str_x="" # string version of "x"
typeset str_y="" # string version of "y"
for (( res=16. ; str_x == str_y ; res=res/2. )) ; do
(( x=y=8.*res ))
# convert x and y to their string representation
str_x="$x"
str_y="$y"
done
printf "%f != %f\n" "str_x" "str_y"
printf "%a != %a\n" "str_x" "str_y"
printf "res=%f\n" res
exit 0
-- snip --
The program does the following:
There are two variables "x" and "y" which hold an identical value in the
internal |long double| storage.
The value is then converted to a base10 representation for "x" (declared
as "float x") and this string stored in "str_x".
The same value is converted to a base16 (C99 hexfloat) representation
(declared as "typeset -lX") and this string stored in "str_y".
The "for(( ; ; ))" loop then cycles until the expression (( str_x ==
str_y )) returns "false" - which can only happen if the conversion of
the strings in "str_x" and "str_y" back to the internal |long double|
results in a difference.
On 64bit SPARC (where |long double| is 128bit) this application prints:
-- snip --
0.000030 != 0.000030
0x1.00000000b424dc35095cd80f5385p-15 !=
0x1.0000000000000000000000000000p-15
res=0.000001
-- snip --
Or short: $ typeset -X varname # (and/or $ printf "%a" varname #) is
usefull in cases where you need to "serialise" floating-point values
into strings but still need the accurate floating-point value when you
convert it back to an internal variable (the difference above looks tiny
but these tiny differences may ruin applications).
----
Bye,
Roland
--
__ . . __
(o.\ \/ /.o) [email protected]
\__\/\/__/ MPEG specialist, C&&JAVA&&Sun&&Unix programmer
/O /==\ O\ TEL +49 641 3992797
(;O/ \/ \O;)
_______________________________________________
ast-users mailing list
[email protected]
https://mailman.research.att.com/mailman/listinfo/ast-users