Skip to content

Commit 4e5755d

Browse files
committed
BIFs: implement float to big integer support
Allow functions such as trunc, round, etc... to return a big integer, when a number above 2^63 or below -2^63 is given. Signed-off-by: Davide Bettio <davide@uninstall.it>
1 parent c127854 commit 4e5755d

File tree

7 files changed

+37
-10
lines changed

7 files changed

+37
-10
lines changed

src/libAtomVM/bif.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1273,6 +1273,13 @@ static term float_to_integer_helper(
12731273
#else
12741274
return make_maybe_boxed_int(ctx, fail_label, live, fresult);
12751275
#endif
1276+
} else {
1277+
intn_digit_t res[INTN_MAX_RES_LEN];
1278+
intn_integer_sign_t sign;
1279+
size_t len = intn_from_double(fresult, res, &sign);
1280+
if (LIKELY(len > 0)) {
1281+
return make_bigint(ctx, fail_label, live, res, len, sign);
1282+
}
12761283
}
12771284
}
12781285

src/libAtomVM/intn.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ int intn_parse(
7171
const char buf[], size_t buf_len, int base, intn_digit_t *out, intn_integer_sign_t *out_sign);
7272

7373
double intn_to_double(const intn_digit_t *num, size_t len, intn_integer_sign_t sign);
74+
int intn_from_double(double dnum, intn_digit_t *out, intn_integer_sign_t *out_sign);
7475

7576
static inline void intn_copy(
7677
const intn_digit_t *num, size_t num_len, intn_digit_t *out, size_t extend_to)

tests/erlang_tests/bigint.erl

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ start() ->
4848
test_mul() +
4949
parse_bigint() +
5050
test_cmp() +
51-
conv_to_float().
51+
conv_to_from_float().
5252

5353
test_mul() ->
5454
Expected_INT64_MIN = ?MODULE:pow(-2, 63),
@@ -516,14 +516,17 @@ sort([Pivot | T]) ->
516516
sort([]) ->
517517
[].
518518

519-
conv_to_float() ->
519+
conv_to_from_float() ->
520+
% to float
521+
520522
Int0 = ?MODULE:id(erlang:binary_to_integer(?MODULE:id(<<"1000000000000000000">>), 16)),
521523
Int1 = ?MODULE:id(
522524
erlang:binary_to_integer(?MODULE:id(<<"CAFECAFE1234000000000000000000">>), 16)
523525
),
524526
Int2 = ?MODULE:id(
525527
erlang:binary_to_integer(?MODULE:id(<<"-CAFECAFE1234000000000000000000">>), 16)
526528
),
529+
Int3 = ?MODULE:mul(?MODULE:id(Int1), 2),
527530
Num1 = ?MODULE:mul(?MODULE:id(Int1), ?MODULE:id(erlang:binary_to_float(?MODULE:id(<<"1.0">>)))),
528531
Num2 = ?MODULE:mul(?MODULE:id(Int2), ?MODULE:id(erlang:binary_to_float(?MODULE:id(<<"1.0">>)))),
529532
Num3 = ?MODULE:id(Int1) * ?MODULE:id(erlang:binary_to_float(?MODULE:id(<<"2.0">>))),
@@ -536,6 +539,22 @@ conv_to_float() ->
536539
true =
537540
erlang:binary_to_integer(?MODULE:id(<<"195FD95FC2468">>), 16) =:=
538541
?MODULE:divtrunc(?MODULE:id(Num3), Int0),
542+
543+
% from float
544+
545+
Int1 = ?MODULE:id(trunc(?MODULE:id(Num1))),
546+
Int2 = ?MODULE:id(round(?MODULE:id(Num2))),
547+
Int3 = ?MODULE:id(floor(?MODULE:id(Num3))),
548+
Int3 = ?MODULE:id(ceil(?MODULE:id(Num3))),
549+
550+
Int64Max = ?MODULE:id(erlang:binary_to_integer(?MODULE:id(<<"7FFFFFFFFFFFFFFF">>), 16)),
551+
true = (Int64Max >= ?MODULE:id(trunc(?MODULE:id(9223372036854775295.0)))),
552+
true = (Int64Max < ?MODULE:id(trunc(?MODULE:id(9223372036854775296.0)))),
553+
554+
Int64Min = ?MODULE:id(erlang:binary_to_integer(?MODULE:id(<<"-8000000000000000">>), 16)),
555+
true = (Int64Min =< ?MODULE:id(trunc(?MODULE:id(-9223372036854776832.0)))),
556+
true = (Int64Min > ?MODULE:id(trunc(?MODULE:id(-9223372036854776833.0)))),
557+
539558
0.
540559

541560
divtrunc(X, Y) ->

tests/erlang_tests/ceilfloatovf.erl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@
2323
-export([start/0]).
2424

2525
start() ->
26-
to_int(id(id([1.0e+20, 0]))).
26+
to_int(id(id([1.0e+280, 0]))).
2727

2828
to_int(A) ->
2929
try ceil(id(A)) of
3030
B when is_integer(B) ->
3131
"BEAM" = erlang:system_info(machine),
32-
"100000000000000000000" = integer_to_list(B),
32+
281 = length(integer_to_list(B)),
3333
0;
3434
_Other ->
3535
1

tests/erlang_tests/floorfloatovf.erl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@
2323
-export([start/0]).
2424

2525
start() ->
26-
to_int(id(id([1.0e+20, 0]))).
26+
to_int(id(id([-1.0e+257, 0]))).
2727

2828
to_int(A) ->
2929
try floor(id(A)) of
3030
B when is_integer(B) ->
3131
"BEAM" = erlang:system_info(machine),
32-
"100000000000000000000" = integer_to_list(B),
32+
259 = length(integer_to_list(B)),
3333
0;
3434
_Other ->
3535
1

tests/erlang_tests/roundfloatovf.erl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@
2323
-export([start/0]).
2424

2525
start() ->
26-
to_int(id(id([1.0e+20, 0]))).
26+
to_int(id(id([1.0e+300, 0]))).
2727

2828
to_int(A) ->
2929
try round(id(A)) of
3030
B when is_integer(B) ->
3131
"BEAM" = erlang:system_info(machine),
32-
"100000000000000000000" = integer_to_list(B),
32+
301 = length(integer_to_list(B)),
3333
0;
3434
_Other ->
3535
1

tests/erlang_tests/truncfloatovf.erl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@
2323
-export([start/0]).
2424

2525
start() ->
26-
to_int(id(id([1.0e+20, 0]))).
26+
to_int(id(id([1.0e+257, 0]))).
2727

2828
to_int(A) ->
2929
try trunc(id(A)) of
3030
B when is_integer(B) ->
3131
"BEAM" = erlang:system_info(machine),
32-
"100000000000000000000" = integer_to_list(B),
32+
258 = length(integer_to_list(B)),
3333
0;
3434
_Other ->
3535
1

0 commit comments

Comments
 (0)