1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
sub float_conv_old {
    my $hex_str = shift(@_);

    $_ = $hex_str;

    my $d;
    # re-oder string... Alpha is "middle endian"
    $d .= sprintf "%0.8b%0.8b", hex($2), hex($1) while /(..)(..)/g;
    my @bits = split(//, $d);
    push(@bits, (0) x (48 - @bits));

    my($s, $x, $a, $b, $c);
    foreach my $tuple (
        [\$s,   $bits[0]     ],
        [\$x,   @bits[1..8]  ],
        [\$a,   @bits[9..15] ],
        [\$b,   @bits[16..31]],
        [\$c,   @bits[32..47]],
    ) {
        my($var, @bits) = @$tuple;

        my $i = 0;
        foreach my $bit (reverse @bits) {
            $$var += $bit * 2 ** $i;
            $i++;
        }
    }

    return 0 if ($a == 0 and $b == 0 and $x == 0);
    my $new_x = $x - 128;
    #print "$a, $b, $c, ex = $x -- "; #debuging code, for when I forget how this works

    my $result   = new Math::BigFloat 
    my $mantissa = new Math::BigFloat 0;
    $mantissa += 1;
    $mantissa += $a * 2 ** -7;
    $mantissa += $b * 2 ** -23;
    $mantissa += $c * 2 ** -39;

    #print "mant = $mantissa -- "; #see above

    $result   += $s ? -1 : 1;
    $result   *= $mantissa;
    $result   *= 2 ** ($x - 129);

    return $result;
}

use Inline C => <<'END_C';

#include <stdlib.h>
#include <math.h>

double float_conv(char * bits) {
    char * pEnd;
    int sign, exp;
    long long num;
    long long a, b;
    double mant;
    num = strtoll(bits, &pEnd, 16);
    a = num & 0x00ff00ff00ff;
    b = num & 0xff00ff00ff00;
    a <<= 8;
    b >>= 8;
    num = a | b;
    sign =   num & 0x800000000000;
    exp  = ((num & 0x7f8000000000) >> 39) - 129;
    mant = (double) ((num & 0x007fffffffff) | 0x008000000000);
    mant = (double) (mant * pow(2, exp - 39));
    //return ((exp && num) ? (mant * (sign ? -1 : 1)) : 0);
    if (exp == -129 && num == 0) { return 0; }
    return (mant * (sign ? -1 : 1));
}

END_C