Version 1 of IEEE binary float to string conversion

Updated 2001-06-28 10:32:04

From a post in news:comp.lang.tcl :

Floating point values are usually transferred in IEEE format. I have written the following code to read an IEEE float value for the case that your machine doesn't use IEEE natively.

 proc IEEE2float {data byteorder} {
    if {$byteorder == 0} {
        set code [binary scan $data cccc se1 e2f1 f2 f3]
    } else {
        set code [binary scan $data cccc f3 f2 e2f1 se1]
    }

    set se1  [expr {($se1 + 0x100) % 0x100}]
    set e2f1 [expr {($e2f1 + 0x100) % 0x100}]
    set f2   [expr {($f2 + 0x100) % 0x100}]
    set f3   [expr {($f3 + 0x100) % 0x100}]

    set sign [expr {$se1 >> 7}]
    set exponent [expr {(($se1 & 0x7f) << 1 | ($e2f1 >> 7))}]
    set f1 [expr {$e2f1 & 0x7f}]

    set fraction [expr {double($f1)*0.0078125 + \
            double($f2)*3.0517578125e-05 + \
            double($f3)*1.19209289550781e-07}]

    set res [expr {($sign ? -1. : 1.) * \
            pow(2.,double($exponent-127)) * \
            (1. + $fraction)}]
    return $res
 }

It expects a binary buffer containing an IEEE number and the byte order the number is in (0 for big-endian and 1 for little-endian).

3fa22435 yields 1.2667299509 (big-endian) or 6.1330860035e-07 (little).

 + Frank Pilhofer                        [email protected]   +
 |                                      http://www.uni-frankfurt.de/~fp/

1750A to Float Conversion

To go along with converting to IEEE floating point here are two Tcl procedures to convert to and from a MIL-STD-1750A 32-bit floating number. The procedure 1750afloat take a integer value (1750a) and returns the floating point representation. The procedure float1750a take a floating point number and returns the integer representation of the 1750a value

 if {0} {
  1750A floating point numbers are representd as a fractional 
  mantissa times 2 rasied to the power of the exponent.  
  The 32-bit format is:
    MSB                                   LSB
    smmm mmmm mmmm mmmm mmmm mmmm seee eeee
    0                                     31
 } 

 proc 1750afloat {input_word} {
    if {![string is integer $input_word]} {
        return "invalid input: \"$input_word\" not a integer"
    }
    set mantissa [expr $input_word >> 8]
    set exponent [expr ($input_word & 0xff)]
    if {[expr $exponent & 0x80] != 0} {
        set exponent [expr int($exponent - 256)]
    }
    set realnum [expr $mantissa * pow(2, $exponent - 23)]
    return $realnum
 }

 proc float1750a {realnum} {
    if {![string is double $realnum]} {
        return "invalid input: \"$realnum\" not a double"
    }
    if {$realnum == 0} {
        set output_word 0
    } else {
        set exponent [expr int(ceil(log(abs($realnum)) / log(2.)))]
        set mantissa [expr round($realnum / pow(2, $exponent - 23))]
        #boundary condition check and repair at 0x800000
        if {$mantissa == 8388608} {
            set mantissa [expr $mantissa / 2]
            incr exponent
        }
        set output_word [expr ($mantissa << 8) | ($exponent & 0xff)]
    }
    return $output_word
 }

# examples per MIL-STD-1750A section 4.1.5

 format %X [float1750a [expr .9999999 * pow(2,127)]] ;#7FFFFF7F
 format %X [float1750a [expr .5 * pow(2,127)]] ;#4000007F
 format %X [float1750a [expr .625 * pow(2,4)]] ;#50000004
 format %X [float1750a [expr .5 * pow(2,1)]] ;#40000001
 format %X [float1750a [expr .5 * pow(2,0)]] ;#40000000
 format %X [float1750a [expr .5 * pow(2,-1)]] ;#400000FF
 format %X [float1750a [expr .5 * pow(2,-128)]] ;#40000080
 format %X [float1750a [expr .0 * pow(2,0)]] ;#0
 format %X [float1750a [expr -1.0 * pow(2,0)]] ;#80000000
 format %X [float1750a [expr -.5000001 * pow(2,-128)]] ;#BFFFFF80
 format %X [float1750a [expr -.7500001 * pow(2,4)]] ;#9FFFFF04

# wrap test of the procedures

 1750afloat [float1750a 1.222332] ;#1.22233200073

Michael Jacobson ~ [email protected]