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) roland.mainz at nrubsig.org \__\/\/__/ MPEG specialist, C&&JAVA&&Sun&&Unix programmer /O /==\ O\ TEL +49 641 3992797 (;O/ \/ \O;)