gyuunyuu
gyuunyuu

Reputation: 694

TCL: A variable stores a hex value that represents a floating point number, how can this be printed on screen as a float?

The 0x3f800000 represents 1.0 in single precision floating maths. I tried this but could not get the correct result from the program:

set x 0x3f800000
set y [expr double($x)]
puts $y

I just want to "cast" the value of x into a float so it will print on screen as float. How do I do this in tcl?

Please note that in the original problem that I am trying to solve, a tcl script reads value from a hardware register in Quartus II System Console debug system. However, I have given a simple example code to make it easy for others to understand what I need to do.

Upvotes: 0

Views: 561

Answers (2)

Schelte Bron
Schelte Bron

Reputation: 4813

You can obtain the floating point value by converting the integer to a 4-byte binary string and then converting the binary string to a float:

set x 0x3f800000
binary scan [binary format i $x] f y
puts $y

Upvotes: 4

glenn jackman
glenn jackman

Reputation: 247022

There's nothing builtin for that. But some time at https://en.wikipedia.org/wiki/Single-precision_floating-point_format led me to:

proc binary32_to_double {value} {
    set sign [expr {($value & 0b10000000000000000000000000000000) >> 31}]
    set exp  [expr {($value & 0b01111111100000000000000000000000) >> 23}]
    set frac [expr {($value & 0b00000000011111111111111111111111) >>  0}]

    set frac_bits [format {%023b} $frac]
    set fraction 1.0

    for {set i 1} {$i <= 23} {incr i} {
        set bit [string range $frac_bits $i-1 $i-1]
        set fraction [expr {$fraction + $bit * 2**double(-$i)}]
    }

    expr {(-1)**$sign * 2**double($exp - 127) * $fraction}
}

And demonstrating:

% binary32_to_double 0x3f800000
1.0
% binary32_to_double 0b00111110001000000000000000000000
0.15625
% binary32_to_double 0b10111110001000000000000000000000
-0.15625

And we can turn that an expr function like this:

proc ::tcl::mathfunc::binary32 {value} {
    binary32_to_double $value
    # or, put that proc body here
}

So that:

set x 0x3f800000
set y [expr {binary32($x)}]   ;# => 1.0

set x 0b00111110001000000000000000000000
set y [expr {binary32($x)}]   ;# => 0.15625

Upvotes: 1

Related Questions