Dan*_*ohn 11 floating-point perl ieee-754
我有一个项目,其中一个函数接收四个8位字符,并需要将生成的32位IEEE-754浮点数转换为常规Perl数.似乎应该有比下面的工作代码更快的方式,但我还没有找到一个更简单的包函数.
它不起作用,但它似乎很接近:
$float = unpack("f", pack("C4", @array[0..3]); # Fails for small numbers
Run Code Online (Sandbox Code Playgroud)
作品:
@bits0 = split('', unpack("B8", pack("C", shift)));
@bits1 = split('', unpack("B8", pack("C", shift)));
@bits2 = split('', unpack("B8", pack("C", shift)));
@bits3 = split('', unpack("B8", pack("C", shift)));
push @bits, @bits3, @bits2, @bits1, @bits0;
$mantbit = shift(@bits);
$mantsign = $mantbit ? -1 : 1;
$exp = ord(pack("B8", join("",@bits[0..7])));
splice(@bits, 0, 8);
# Convert fractional float to decimal
for (my $i = 0; $i < 23; $i++) {
$f = $bits[$i] * 2 ** (-1 * ($i + 1));
$mant += $f;
}
$float = $mantsign * (1 + $mant) * (2 ** ($exp - 127));
Run Code Online (Sandbox Code Playgroud)
谁有更好的方法?
Nic*_*oic 14
我采取相反的方法:忘记打开包装,坚持一点点.
首先,组装你的32位字.根据字节顺序,这可能必须反过来:
my $word = ($byte0 << 24) + ($byte1 << 16) + ($byte2 << 8) + $byte3;
Run Code Online (Sandbox Code Playgroud)
现在提取单词的部分:符号位,指数和尾数:
my $sign = ($word & 0x80000000) ? -1 : 1;
my $expo = (($word & 0x7F800000) >> 23) - 127;
my $mant = ($word & 0x007FFFFF | 0x00800000);
Run Code Online (Sandbox Code Playgroud)
组装你的浮子:
my $num = $sign * (2 ** $expo) * ( $mant / (1 << 23));
Run Code Online (Sandbox Code Playgroud)
维基百科上有一些例子.
最好的方法是使用pack().
my @bytes = ( 0xC2, 0xED, 0x40, 0x00 );
my $float = unpack 'f', pack 'C4', @bytes;
Run Code Online (Sandbox Code Playgroud)
或者,如果源和目标具有不同的字节顺序:
my $float = unpack 'f', pack 'C4', reverse @bytes;
Run Code Online (Sandbox Code Playgroud)
你说这种方法"不起作用 - 它看起来很接近"而"小数字却失败了",但是你没有给出一个例子.我猜你实际看到的是四舍五入的地方,例如,一个数字被打包为1.234,但它被解压缩为1.23399996757507.这不是pack()的函数,而是4字节float的精度.
| 归档时间: |
|
| 查看次数: |
6012 次 |
| 最近记录: |