В 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.