jjmerelo
jjmerelo

Reputation: 23527

In Perl 6, how can I convert from raw bytes to floating point using the NativeCall interface?

From this conversation in the Perl 6 IRC channel and a question posted by Martin Barth, I'm trying to reproduce this C code using the Perl6 NativeCall interface, which is used with that purpose. This is what I have tried:

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 yields an error:

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

Which I interpret as, well, you have declared this as an Integer, I can't turn it into raw memory so that it can be copied from here to there.

This was only a possible way of answering the more general question by Martin Barth: how to turn raw bytes into a floating point number. Maybe there's other way of doing that, but in any case I'd be curious to find out how to turn C programs into NativeCall equivalents.

Update: in the meantime, here's the original question this other post tries to be a solution for.

Upvotes: 9

Views: 196

Answers (1)

Jonathan Worthington
Jonathan Worthington

Reputation: 29454

Using a union (where all fields share the same memory space) is perhaps the most natural way. Declare a union like this:

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

And then use it to do conversion:

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

One other issue unrelated to the meat of the question, but present in the posted code: the native integer and number times never need to have a .new done on them, because they are not object types. This:

my uint32 $num = .new;

Should just be:

my uint32 $num;

And:

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

Should just be:

my num32 $float = 1e0;

The use of the e exponent is what makes a literal a float in Perl 6.

Upvotes: 9

Related Questions