Skip to content

Commit b124e0b

Browse files
committed
Add big integer to double conversion
Refactor term_conv_to_float in order to use intn_to_double function. Also make sure in opcodesswitch that term_conv_to_float() returns a finite value. Signed-off-by: Davide Bettio <davide@uninstall.it>
1 parent 774cb32 commit b124e0b

File tree

5 files changed

+68
-11
lines changed

5 files changed

+68
-11
lines changed

src/libAtomVM/intn.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ char *intn_to_string(const intn_digit_t *num, size_t len, intn_integer_sign_t nu
7070
int intn_parse(
7171
const char buf[], size_t buf_len, int base, intn_digit_t *out, intn_integer_sign_t *out_sign);
7272

73+
double intn_to_double(const intn_digit_t *num, size_t len, intn_integer_sign_t sign);
74+
7375
static inline void intn_copy(
7476
const intn_digit_t *num, size_t num_len, intn_digit_t *out, size_t extend_to)
7577
{

src/libAtomVM/opcodesswitch.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6108,7 +6108,11 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb)
61086108
if (UNLIKELY(!term_is_number(src_value))) {
61096109
RAISE_ERROR(BADARITH_ATOM);
61106110
}
6111-
ctx->fr[freg] = term_conv_to_float(src_value);
6111+
avm_float_t converted = term_conv_to_float(src_value);
6112+
if (UNLIKELY(!isfinite(converted))) {
6113+
RAISE_ERROR(BADARITH_ATOM);
6114+
}
6115+
ctx->fr[freg] = converted;
61126116
#endif
61136117

61146118
#ifdef IMPL_CODE_LOADER

src/libAtomVM/term.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -895,3 +895,34 @@ term term_get_map_assoc(term map, term key, GlobalContext *glb)
895895
}
896896
return term_get_map_value(map, pos);
897897
}
898+
899+
avm_float_t term_conv_to_float(term t)
900+
{
901+
if (term_is_float(t)) {
902+
return term_to_float(t);
903+
} else if (term_is_integer(t)) {
904+
return term_to_int(t);
905+
} else if (term_is_boxed_integer(t)) {
906+
size_t boxed_size = term_boxed_size(t);
907+
switch (boxed_size) {
908+
case 0:
909+
UNREACHABLE();
910+
case 1:
911+
return term_unbox_int(t);
912+
#if BOXED_TERMS_REQUIRED_FOR_INT64 == 2
913+
case 2:
914+
return term_unbox_int64(t);
915+
#endif
916+
default: {
917+
const intn_digit_t *num = (intn_digit_t *) term_intn_data(t);
918+
size_t digits_per_term = (sizeof(term) / sizeof(intn_digit_t));
919+
size_t len = boxed_size * digits_per_term;
920+
term_integer_sign_t t_sign = term_boxed_integer_sign(t);
921+
922+
return intn_to_double(num, len, (intn_integer_sign_t) t_sign);
923+
}
924+
}
925+
} else {
926+
UNREACHABLE();
927+
}
928+
}

src/libAtomVM/term.h

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1566,15 +1566,6 @@ static inline avm_float_t term_to_float(term t)
15661566
return boxed_float->f;
15671567
}
15681568

1569-
static inline avm_float_t term_conv_to_float(term t)
1570-
{
1571-
if (term_is_any_integer(t)) {
1572-
return term_maybe_unbox_int64(t);
1573-
} else {
1574-
return term_to_float(t);
1575-
}
1576-
}
1577-
15781569
static inline bool term_is_number(term t)
15791570
{
15801571
return term_is_any_integer(t) || term_is_float(t);
@@ -1624,6 +1615,8 @@ int term_fprint(FILE *fd, term t, const GlobalContext *global);
16241615
*/
16251616
int term_snprint(char *buf, size_t size, term t, const GlobalContext *global);
16261617

1618+
avm_float_t term_conv_to_float(term t);
1619+
16271620
/**
16281621
* @brief Checks if a term is a string (i.e., a list of characters)
16291622
*

tests/erlang_tests/bigint.erl

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
sort/1,
2828
twice/1,
2929
fact/1,
30+
divtrunc/2,
3031
the_out_of_order_list/0,
3132
the_ordered_list/0,
3233
get_machine_atom/0,
@@ -46,7 +47,8 @@
4647
start() ->
4748
test_mul() +
4849
parse_bigint() +
49-
test_cmp().
50+
test_cmp() +
51+
conv_to_float().
5052

5153
test_mul() ->
5254
Expected_INT64_MIN = ?MODULE:pow(-2, 63),
@@ -514,6 +516,31 @@ sort([Pivot | T]) ->
514516
sort([]) ->
515517
[].
516518

519+
conv_to_float() ->
520+
Int0 = ?MODULE:id(erlang:binary_to_integer(?MODULE:id(<<"1000000000000000000">>), 16)),
521+
Int1 = ?MODULE:id(
522+
erlang:binary_to_integer(?MODULE:id(<<"CAFECAFE1234000000000000000000">>), 16)
523+
),
524+
Int2 = ?MODULE:id(
525+
erlang:binary_to_integer(?MODULE:id(<<"-CAFECAFE1234000000000000000000">>), 16)
526+
),
527+
Num1 = ?MODULE:mul(?MODULE:id(Int1), ?MODULE:id(erlang:binary_to_float(?MODULE:id(<<"1.0">>)))),
528+
Num2 = ?MODULE:mul(?MODULE:id(Int2), ?MODULE:id(erlang:binary_to_float(?MODULE:id(<<"1.0">>)))),
529+
Num3 = ?MODULE:id(Int1) * ?MODULE:id(erlang:binary_to_float(?MODULE:id(<<"2.0">>))),
530+
true =
531+
erlang:binary_to_integer(?MODULE:id(<<"CAFECAFE1234">>), 16) =:=
532+
?MODULE:divtrunc(?MODULE:id(Num1), Int0),
533+
true =
534+
erlang:binary_to_integer(?MODULE:id(<<"-CAFECAFE1234">>), 16) =:=
535+
?MODULE:divtrunc(?MODULE:id(Num2), Int0),
536+
true =
537+
erlang:binary_to_integer(?MODULE:id(<<"195FD95FC2468">>), 16) =:=
538+
?MODULE:divtrunc(?MODULE:id(Num3), Int0),
539+
0.
540+
541+
divtrunc(X, Y) ->
542+
erlang:trunc(X / Y).
543+
517544
id(X) ->
518545
X.
519546

0 commit comments

Comments
 (0)