1
votes

I'm experimenting with NIFs and I'm confused about what number types Erlang is working with, because I'm getting some weirdness with my precisions.

Here's an example:

erlang:band(18446744073709551614, 5) == 4

And from inside a NIF which looks something like this:

long long l, r;

enif_get_long(env, argv[0], &l);
enif_get_long(env, argv[1], &r);

return enif_make_long(env, l & r);

I get a 1 as a result.

Is this something to do with the C layer not holding the correct "size" of the number? Or is it that enif_(get|make)_long isn't the correct way to be dealing with a number of this size? Or is it simply that NIFs can't work with numbers this large?

1

1 Answers

4
votes

18446744073709551614 is 2^64 - 2 and therefore cannot fit in a long long, which is most likely a 64 bit signed integer with the range -(2^63) to (2^63)-1. Also, enif_get_long requires a long int, not long long. You should also be getting an error value returned from enif_get_long because of the overflow according to the docs which you are not checking for.

To work on numbers upto 2^64 - 1 (which includes the number in question), you can use enif_get_uint64.

This code should work (untested):

ErlNifUInt64 l, r;
enif_get_uint64(env, argv[0], &l);
enif_get_uint64(env, argv[1], &r);
return enif_make_uint64(env, l & r);

You should also check the return value of enif_get_* to make sure you're not working on uninitialized data.