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;
$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;
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;
$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
|