Как я могу преобразовать четыре символа в 32-разрядное плавание IEEE 754 в Perl?

PHP может распознавать конечные числа в строках и хорошо справляться с перегрузкой операторов.

$strNum = "Next year is 2019";

$strNum++;   // Next year is 2020
11
задан Peter Mortensen 4 August 2017 в 21:08
поделиться

2 ответа

I'd take the opposite approach: forget unpacking, stick to bit twiddling.

First, assemble your 32 bit word. Depending on endianness, this might have to be the other way around:

my $word = ($byte0 << 24) + ($byte1 << 16) + ($byte2 << 8) + $byte3;

Now extract the parts of the word: the sign bit, exponent and mantissa:

my $sign = ($word & 0x80000000) ? -1 : 1;
my $expo = (($word & 0x7F800000) >> 23) - 127;
my $mant = ($word & 0x007FFFFF | 0x00800000);

Assemble your float:

my $num = $sign * (2 ** $expo) * ( $mant / (1 << 23));

There's some examples on Wikipedia.

  • Tested this on 0xC2ED4000 => -118.625 and it works.
  • Tested this on 0x3E200000 => 0.15625 and found a bug! (fixed)
  • Don't forget to handle infinities and NaNs when $expo == 255
14
ответ дан 3 December 2019 в 06:22
поделиться

Лучший способ сделать это - использовать pack () .

my @bytes = ( 0xC2, 0xED, 0x40, 0x00 );
my $float = unpack 'f', pack 'C4', @bytes;

Или если источник и назначение имеют различный порядок байтов:

my $float = unpack 'f', pack 'C4', reverse @bytes;

Вы говорите, что этот метод «не работает - кажется, что он близок» и «терпит неудачу для небольших чисел», но вы не приводите пример. Я предполагаю, что на самом деле вы видите округление, где, например, число упаковано как 1.234, но распаковано как 1.23399996757507. Это не функция pack (), а точность 4-байтового числа с плавающей запятой.

5
ответ дан 3 December 2019 в 06:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: