这是以下变体:
在这个问题中,我们想要从二进制文件打印 IEEE 754 单精度(即 32 位)浮点值。
现在假设我想打印半精度(即16位)浮点数。
od
似乎不喜欢这样做:
$ od -t f2 c.bin
od: invalid type string ‘f2’;
this system doesn't provide a 2-byte floating point type
perl 的包 也没有...
如果您的答案还涵盖具有 bfloat16(也是 16 位)值的二进制文件,则会加分。
以下是 SO 的“Ask with AI”为 IEEE 754 半精度生成的代码(我问了 2 个不同的问题,合并了代码,并添加了缺失的导入):
#!/usr/bin/env python3
import struct
import sys
def half_to_double(half):
# Pack the half-precision number into bytes
packed_half = struct.pack('H', half)
# Unpack the bytes into the corresponding format
unpacked_half = struct.unpack('e', packed_half)[0]
# Convert the unpacked value to double-precision
double = float(unpacked_half)
return double
# Read 2 bytes from stdin
data = sys.stdin.buffer.read(2)
# Unpack the bytes into a 2-byte integer
half_number = struct.unpack('<h', data)[0]
double_number = half_to_double(half_number)
print(double_number)
在 bash 或 zsh 下测试(用于
printf
\x
支持),为小端机器订购 2 个字节:
vlefevre@cventin:~$ printf "\x00\x00" | ./tst.py
0.0
vlefevre@cventin:~$ printf "\x00\x3c" | ./tst.py
1.0
vlefevre@cventin:~$ printf "\x01\x3c" | ./tst.py
1.0009765625
vlefevre@cventin:~$ printf "\xff\x7b" | ./tst.py
65504.0
这可以通过维基百科上半精度浮点格式给出的示例进行检查。
这也是 Perl 的版本,但仅适用于普通数字。该代码也是由 SO 的“Ask with AI”生成的,但它是错误的(它混合了 32 位和 64 位数字),所以我必须修复它(并适应问题的开头)。
#!/usr/bin/env perl
use strict;
# Code from SO's "Ask with AI" with various fixes.
# For normal numbers only!
# Read the binary16 number from stdin
my $binary16;
read(STDIN, $binary16, 2) == 2 or die;
# Convert the binary16 number to an unsigned short integer
my $unsigned_short = unpack 'S', $binary16;
printf "%04X\n", $unsigned_short;
# Extract the sign bit, exponent, and significand from the unsigned short
my $sign = ($unsigned_short & 0x8000) >> 15;
my $exponent = ($unsigned_short & 0x7C00) >> 10;
my $significand = $unsigned_short & 0x03FF;
# Convert the binary16 components to binary32 components
my $exponent_bias = 15; # Bias for the binary16 exponent
my $exponent_offset = 127; # Offset for the binary32 exponent
my $binary32_sign = $sign;
my $binary32_exponent = ($exponent - $exponent_bias) + $exponent_offset;
my $binary32_significand = $significand << 13;
print "$sign $exponent $significand\n";
# Combine the binary32 components into a binary string
my $binary32_string = pack 'N',
$binary32_sign << 31 | $binary32_exponent << 23 | $binary32_significand;
# Unpack the binary string as a float
my $converted_number = unpack 'f>', $binary32_string;
print "$converted_number\n";
对于bfloat16,这更简单,因为它可以被视为binary32二进制字符串的截断。因此只需将 2 字节整数向左移动 16 位(即在右侧插入 16 个零)。这是代码:
#!/usr/bin/env perl
use strict;
# Read the bfloat16 number from stdin
my $bfloat16;
read(STDIN, $bfloat16, 2) == 2 or die;
# Convert the bfloat16 number to an unsigned short integer
my $unsigned_short = unpack 'S', $bfloat16;
printf "%04X\n", $unsigned_short;
my $binary32_string = pack 'N', $unsigned_short << 16;
# Unpack the binary32 string as a float
my $converted_number = unpack 'f>', $binary32_string;
print "$converted_number\n";
这可以在维基百科上的bfloat16浮点格式的示例中进行检查。
GNU coreutils 将在 9.5 版本中添加对此的支持,分别使用 -tfH 和 -tfB 类型:
$ printf '\x3F\x80\x00\x00' | od -An --endian=big -tfH -tf2 -tfB -tfF
1.875 0
1.875 0
1 0
1