В Perl 6, как я могу преобразовать необработанные байты в число с плавающей запятой, используя интерфейс NativeCall?

Из этого разговора на канале Perl 6 IRC и вопроса, опубликованного Мартином Бартом, я пытаюсь воспроизвести этот код C, используя интерфейс Perl6 NativeCall, который используется для этой цели. Вот что я попробовал:

use NativeCall;

my uint32 $num = .new;
my num32 $float = .new: Num(1.0);

sub memcpy(num32 $float, uint32 $num, int32 $size) is native('Str') { * };

memcpy($float,$num,4);
say $num;

Это приводит к ошибке:

This type cannot unbox to a native integer: P6opaque, Any

Что я интерпретирую как, ну, вы объявили это как целое число, я не могу превратить его в сырую память, чтобы его можно было скопировать отсюда туда.

Это был только возможный способ ответить на более общий вопрос Мартина Барта: как превратить необработанные байты в число с плавающей запятой. Возможно, есть и другой способ сделать это, но в любом случае мне было бы любопытно узнать, как превратить программы на C в эквиваленты NativeCall.

Обновление: тем временем, вот оригинальный вопрос, для которого этот другой пост пытается решить.

1 ответ

Решение

Использование объединения (где все поля разделяют одно и то же пространство памяти), возможно, является наиболее естественным способом. Объявите союз так:

my class Convertor is repr<CUnion> {
    has uint32 $.i is rw;
    has num32 $.n is rw;
}

И затем используйте это, чтобы сделать преобразование:

my $c = Convertor.new;
$c.i = 0b1000010111101101100110011001101;
say $c.n  # 123.4000015258789

Еще одна проблема, не относящаяся к сути вопроса, но присутствующая в размещенном коде: родное целое число и число раз никогда не должны иметь .new сделано на них, потому что они не являются типами объектов. Это:

my uint32 $num = .new;

Должно быть просто:

my uint32 $num;

А также:

my num32 $float = .new: Num(1.0);

Должно быть просто:

my num32 $float = 1e0;

Использование e Экспонент - это то, что делает буквальное число плавающим в Perl 6.

Другие вопросы по тегам