Version 2 of IEEE floating numbers

Updated 2004-12-20 18:16:00 by msw
 # procedures to show internal IEEE standard "double" representation #
 #####################################################################

 # big endian code

 proc floatToBinarBigEndian {d} {
     binary scan [binary format d $d] B* v
     set sign [string index $v 0]
     set exponent [string range $v 1 11]
     set mantissa [string range $v 12 end]
     return [list $sign $mantissa $exponent]
 }

 proc binarToFloatBigEndian {sign mantissa exponent} {
     if {$sign != "0" && $sign != "1"} {
         error "bad sign \"$sign\""
     }
     if {[string length $mantissa] != 52} {
         error "bad mantissa \"$mantissa\""
     }
     if {[string length $exponent] != 11} {
         error "bad exponent \"$exponent\""
     }
     set v [binary format B64 $sign$exponent$mantissa]
     binary scan $v d v
     return $v
 }

 # little endian code

 proc __reverse__ {s} {
     for {set i [string length $s]} {$i>=0} {incr i -1} {
         append sr [string index $s $i]
     }
     return $sr
 }

 proc floatToBinarLittleEndian {d} {
     binary scan [binary format d $d] b* v
     set v [__reverse__ $v]
     set sign [string index $v 0]
     set exponent [string range $v 1 11]
     set mantissa [string range $v 12 end]
     return [list $sign $mantissa $exponent]
 }

 proc binarToFloatLittleEndian {sign mantissa exponent} {
     if {$sign != "0" && $sign != "1"} {
         error "bad sign \"$sign\""
     }
     if {[string length $mantissa] != 52} {
         error "bad mantissa \"$mantissa\""
     }
     if {[string length $exponent] != 11} {
         error "bad exponent \"$exponent\""
     }
     set v [binary format b64 [__reverse__ $sign$exponent$mantissa]]
     binary scan $v d v
     return $v
 }

 # platform independent procedures #

 proc floatToBinar {d} {
     global tcl_platform
     switch $tcl_platform(byteOrder) {
         "bigEndian" {return [floatToBinarBigEndian $d]}
         "littleEndian" {return [floatToBinarLittleEndian $d]}
         default {return -code error "unknown byteOrder \"$tcl_platform(byteOrder)\""}
     }
 }

 proc binarToFloat {sign mantissa exponent} {
     global tcl_platform
     switch $tcl_platform(byteOrder) {
         "bigEndian" {return [binarToFloatBigEndian $sign $mantissa $exponent]}
         "littleEndian" {return [binarToFloatLittleEndian $sign $mantissa $exponent]}
         default {return -code error "unknown byteOrder \"$tcl_platform(byteOrder)\""}
     }
 }

 proc floatToBinarTest {value sign mantissa exponent} {
     set r [floatToBinar $value]
     if {
         [lindex $r 0] != $sign ||
         [lindex $r 1] != $mantissa ||
         [lindex $r 2] != $exponent
     } {
         return -code error "this machine is not IEEE floating point compliant"
     }
 }

 # Some tests

 floatToBinarTest  1.0      0 0000000000000000000000000000000000000000000000000000 01111111111
 floatToBinarTest -1.0      1 0000000000000000000000000000000000000000000000000000 01111111111

 # An example why you should put braces around "expr" argument

 set tcl_precision 12
 set pi [expr {acos(-1.0)}]
 floatToBinarTest $pi           0 1001001000011111101101010100010001000010110100011000 10000000000
 floatToBinarTest [expr {$pi}]  0 1001001000011111101101010100010001000010110100011000 10000000000
 floatToBinarTest [expr $pi]    0 1001001000011111101101010100010001000010111011101010 10000000000

 # the 17 digits string representation is exact

 set tcl_precision 17
 set pi [expr {acos(-1.0)}]
 floatToBinarTest $pi           0 1001001000011111101101010100010001000010110100011000 10000000000
 floatToBinarTest [expr {$pi}]  0 1001001000011111101101010100010001000010110100011000 10000000000
 floatToBinarTest [expr $pi]    0 1001001000011111101101010100010001000010110100011000 10000000000 

 puts [binarToFloat 0 1001001000011111101101010100010001000010110100010111 10000000000] ;# 3.1415926535897927
 puts [binarToFloat 0 1001001000011111101101010100010001000010110100011000 10000000000] ;# 3.1415926535897931
 puts [binarToFloat 0 1001001000011111101101010100010001000010110100011001 10000000000] ;# 3.1415926535897936 

 puts [binarToFloat 0 1001001000011111101101010100010001000010110100010111 10000000000] ;# 3.1415926535897927
 puts [binarToFloat 0 1001001000011111101101010100010001000010110100011000 10000000000] ;# 3.1415926535897931
 puts [binarToFloat 0 1001001000011111101101010100010001000010110100011001 10000000000] ;# 3.1415926535897936 

 # Special representations

 binarToFloat 0 0000000000000000000000000000000000000000000000000000 00000000000        ;# 0.0
 binarToFloat 0 0000000000000000000000000000000000000000000000000001 00000000000        ;# 4.9406564584124654e-324
 binarToFloat 0 1111111111111111111111111111111111111111111111111111 00000000000        ;# 2.2250738585072009e-308
 binarToFloat 0 0000000000000000000000000000000000000000000000000000 00000000001        ;# 2.2250738585072014e-308
 binarToFloat 0 0000000000000000000000000000000000000000000000000000 11111111110        ;# 8.9884656743115795e+307
 binarToFloat 0 1111111111111111111111111111111111111111111111111111 11111111110        ;# 1.7976931348623157e+308
 binarToFloat 0 0000000000000000000000000000000000000000000000000000 11111111111        ;# inf
 binarToFloat 1 0000000000000000000000000000000000000000000000000000 11111111111        ;# -inf
 binarToFloat 0 1111111111111111111111111111111111111111111111111111 11111111111        ;# nan
 binarToFloat 1 1111111111111111111111111111111111111111111111111111 11111111111        ;# nan

-- [ Computers and real numbers ]