Skip to content

Commit db12deb

Browse files
committed
Make bsr work with signed numbers
Signed-off-by: Davide Bettio <davide@uninstall.it>
1 parent b820f6b commit db12deb

File tree

4 files changed

+83
-46
lines changed

4 files changed

+83
-46
lines changed

src/libAtomVM/bif.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1648,7 +1648,7 @@ term bif_erlang_bsr_2(Context *ctx, uint32_t fail_label, int live, term arg1, te
16481648
args_to_bigint(arg1, arg2, tmp_buf1, tmp_buf2, &m, &m_len, &m_sign, &n, &n_len, &n_sign);
16491649

16501650
intn_digit_t bigres[INTN_MAX_RES_LEN];
1651-
size_t bigres_len = intn_bsr(m, m_len, b, bigres);
1651+
size_t bigres_len = intn_bsr(m, m_len, m_sign, b, bigres);
16521652

16531653
return make_bigint(ctx, fail_label, live, bigres, bigres_len, m_sign);
16541654
} else {

src/libAtomVM/intn.c

Lines changed: 70 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@
3535
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
3636
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
3737

38+
static size_t cond_neg_in_place(intn_integer_sign_t sign, intn_digit_t out[]);
39+
static size_t neg_in_place(intn_digit_t out[], size_t len);
40+
3841
/*
3942
* Multiplication
4043
*/
@@ -380,18 +383,23 @@ size_t intn_addmnu(
380383
return i;
381384
}
382385

386+
static void neg(const intn_digit_t in[], size_t in_len, intn_digit_t out[])
387+
{
388+
uint32_t carry = 1;
389+
for (size_t i = 0; i < in_len; i++) {
390+
uint64_t temp = (uint64_t) (~in[i]) + (uint64_t) carry;
391+
out[i] = (uint32_t) temp;
392+
carry = temp >> 32;
393+
}
394+
}
395+
383396
static void cond_neg(
384397
intn_integer_sign_t sign, const intn_digit_t in[], size_t in_len, intn_digit_t out[])
385398
{
386399
if (sign == IntNPositiveInteger) {
387400
memcpy(out, in, sizeof(intn_digit_t) * in_len);
388401
} else {
389-
uint32_t carry = 1;
390-
for (size_t i = 0; i < in_len; i++) {
391-
uint64_t temp = (uint64_t) (~in[i]) + (uint64_t) carry;
392-
out[i] = (uint32_t) temp;
393-
carry = temp >> 32;
394-
}
402+
neg(in, in_len, out);
395403
}
396404
}
397405

@@ -604,21 +612,15 @@ size_t intn_bsl(const uint32_t num[], size_t len, size_t n, uint32_t *out)
604612
return initial_zeros + i;
605613
}
606614

607-
size_t intn_bsr(const uint32_t num[], size_t len, size_t n, uint32_t *out)
615+
size_t bsru(const uint32_t num[], size_t effective_bits_len, size_t n, uint32_t last_digit, uint32_t *out)
608616
{
609617
size_t digit_bit_size = sizeof(uint32_t) * 8;
610618

611619
size_t digit_right_bit_shift = n % 32;
612620
size_t left_shift_n = (32 - digit_right_bit_shift);
613621

614-
size_t counted_digits = intn_count_digits(num, len);
615-
size_t ms_digit_bits = 32 - uint32_nlz(num[counted_digits - 1]);
616-
size_t effective_bits_len = (counted_digits - 1) * digit_bit_size + ms_digit_bits;
617-
618-
if (n > effective_bits_len) {
619-
out[0] = 0;
620-
return 1;
621-
}
622+
size_t len = size_round_to(effective_bits_len, digit_bit_size) / digit_bit_size;
623+
size_t counted_digits = len;
622624

623625
///size_t new_bits_len = size_round_to(effective_bits_len - n, digit_bit_size);
624626

@@ -637,7 +639,7 @@ size_t intn_bsr(const uint32_t num[], size_t len, size_t n, uint32_t *out)
637639
uint32_t digit = num[i];
638640
out[i - discarded] = (digit >> digit_right_bit_shift) | (next_digit << left_shift_n);
639641
}
640-
uint32_t maybe_last_out = (num[i] >> digit_right_bit_shift);
642+
uint32_t maybe_last_out = (num[i] >> digit_right_bit_shift) | (last_digit << left_shift_n);
641643

642644
/*
643645
if (initial_zeros + i > new_digits_count) {
@@ -653,6 +655,35 @@ size_t intn_bsr(const uint32_t num[], size_t len, size_t n, uint32_t *out)
653655
return i - discarded;
654656
}
655657

658+
size_t intn_bsr(const uint32_t num[], size_t len, intn_integer_sign_t num_sign, size_t n, uint32_t *out)
659+
{
660+
size_t digit_bit_size = sizeof(uint32_t) * 8;
661+
size_t counted_digits = intn_count_digits(num, len);
662+
size_t ms_digit_bits = 32 - uint32_nlz(num[counted_digits - 1]);
663+
size_t effective_bits_len = (counted_digits - 1) * digit_bit_size + ms_digit_bits;
664+
665+
if (n > effective_bits_len) {
666+
out[0] = (num_sign == IntNPositiveInteger) ? 0 : 1;
667+
return 1;
668+
}
669+
670+
if (num_sign == IntNPositiveInteger) {
671+
return bsru(num, effective_bits_len, n, 0, out);
672+
} else {
673+
uint32_t tmp_buf[INTN_MAX_RES_LEN];
674+
memset(out, 0, INTN_MAX_RES_LEN * sizeof(const uint32_t));
675+
neg(num, counted_digits, tmp_buf);
676+
size_t shifted_len = bsru(tmp_buf, effective_bits_len, n, (uint32_t) -1, out);
677+
678+
size_t len = size_round_to(effective_bits_len - n, digit_bit_size) / digit_bit_size;
679+
neg_in_place(out, len);
680+
681+
fprintf(stderr, "shifted: %i, len: %i\n", (int) shifted_len, (int) len);
682+
print_num(out, len);
683+
return len;
684+
}
685+
}
686+
656687

657688

658689
/*
@@ -912,26 +943,32 @@ int intn_parse(
912943
return out_len;
913944
}
914945

946+
static size_t neg_in_place(intn_digit_t out[], size_t len)
947+
{
948+
uint32_t carry = 1;
949+
size_t i;
950+
int last_non_zero = -1;
951+
for (i = 0; i < len; i++) {
952+
uint64_t temp = (uint64_t) (~out[i]) + (uint64_t) carry;
953+
if ((uint32_t) temp != 0) {
954+
last_non_zero = i;
955+
}
956+
out[i] = (uint32_t) temp;
957+
carry = temp >> 32;
958+
}
959+
if (carry) {
960+
abort();
961+
out[i] = carry;
962+
return i;
963+
} else {
964+
return last_non_zero + 1;
965+
}
966+
}
967+
915968
static size_t cond_neg_in_place(intn_integer_sign_t sign, intn_digit_t out[])
916969
{
917970
if (sign == IntNNegativeInteger) {
918-
uint32_t carry = 1;
919-
size_t i;
920-
int last_non_zero = -1;
921-
for (i = 0; i < INTN_MAX_RES_LEN - 1; i++) {
922-
uint64_t temp = (uint64_t) (~out[i]) + (uint64_t) carry;
923-
if ((uint32_t) temp != 0) {
924-
last_non_zero = i;
925-
}
926-
out[i] = (uint32_t) temp;
927-
carry = temp >> 32;
928-
}
929-
if (carry) {
930-
out[i] = carry;
931-
return i;
932-
} else {
933-
return last_non_zero + 1;
934-
}
971+
return neg_in_place(out, INTN_MAX_RES_LEN - 1);
935972
} else {
936973
return intn_count_digits(out, INTN_MAX_IN_LEN);
937974
}

src/libAtomVM/intn.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ size_t intn_bxormn(const intn_digit_t m[], size_t m_len, intn_integer_sign_t m_s
8686
intn_integer_sign_t *out_sign);
8787

8888
size_t intn_bsl(const uint32_t num[], size_t len, size_t n, uint32_t *out);
89-
size_t intn_bsr(const uint32_t num[], size_t len, size_t n, uint32_t *out);
89+
size_t intn_bsr(const uint32_t num[], size_t len, intn_integer_sign_t num_sign, size_t n, uint32_t *out);
9090

9191
size_t intn_count_digits(const intn_digit_t *num, size_t num_len);
9292

tests/erlang_tests/bigint.erl

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -952,17 +952,17 @@ test_bsr() ->
952952
<<"0">> = erlang:integer_to_binary(Pattern1 bsr ?MODULE:id(250), 16),
953953
<<"0">> = erlang:integer_to_binary(Pattern1 bsr ?MODULE:id(256), 16),
954954

955-
%Pattern2 = erlang:binary_to_integer(?MODULE:id(<<"-CAFE1234AABBCCDD98765432987654321">>), 16),
956-
%<<"-CAFE1234AABBCCDD98765432988">> = erlang:integer_to_binary(Pattern2 bsr ?MODULE:id(24), 16),
957-
%<<"-657F091A555DE66ECC3B2A194D">> = erlang:integer_to_binary(Pattern2 bsr ?MODULE:id(29), 16),
958-
%<<"-CAFE1234AABBCCDD98765432A">> = erlang:integer_to_binary(Pattern2 bsr ?MODULE:id(32), 16),
959-
%<<"-195FC2469557799BB30ECA866">> = erlang:integer_to_binary(Pattern2 bsr ?MODULE:id(35), 16),
960-
%<<"-CAFE1234AABBCCDD98766">> = erlang:integer_to_binary(Pattern2 bsr ?MODULE:id(48), 16),
961-
%<<"-195FC2469557799BB30ED">> = erlang:integer_to_binary(Pattern2 bsr ?MODULE:id(51), 16),
962-
%<<"-CAFE1234AABBCCDDA">> = erlang:integer_to_binary(Pattern2 bsr ?MODULE:id(64), 16),
963-
%<<"-D">> = erlang:integer_to_binary(Pattern2 bsr ?MODULE:id(128), 16),
964-
%<<"-1">> = erlang:integer_to_binary(Pattern2 bsr ?MODULE:id(250), 16),
965-
%<<"-1">> = erlang:integer_to_binary(Pattern2 bsr ?MODULE:id(256), 16),
955+
Pattern2 = erlang:binary_to_integer(?MODULE:id(<<"-CAFE1234AABBCCDD98765432987654321">>), 16),
956+
<<"-CAFE1234AABBCCDD98765432988">> = erlang:integer_to_binary(Pattern2 bsr ?MODULE:id(24), 16),
957+
<<"-657F091A555DE66ECC3B2A194D">> = erlang:integer_to_binary(Pattern2 bsr ?MODULE:id(29), 16),
958+
<<"-CAFE1234AABBCCDD98765432A">> = erlang:integer_to_binary(Pattern2 bsr ?MODULE:id(32), 16),
959+
<<"-195FC2469557799BB30ECA866">> = erlang:integer_to_binary(Pattern2 bsr ?MODULE:id(35), 16),
960+
<<"-CAFE1234AABBCCDD98766">> = erlang:integer_to_binary(Pattern2 bsr ?MODULE:id(48), 16),
961+
<<"-195FC2469557799BB30ED">> = erlang:integer_to_binary(Pattern2 bsr ?MODULE:id(51), 16),
962+
<<"-CAFE1234AABBCCDDA">> = erlang:integer_to_binary(Pattern2 bsr ?MODULE:id(64), 16),
963+
<<"-D">> = erlang:integer_to_binary(Pattern2 bsr ?MODULE:id(128), 16),
964+
<<"-1">> = erlang:integer_to_binary(Pattern2 bsr ?MODULE:id(250), 16),
965+
<<"-1">> = erlang:integer_to_binary(Pattern2 bsr ?MODULE:id(256), 16),
966966

967967
0.
968968

0 commit comments

Comments
 (0)