1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-03-09 15:40:10 +00:00

Add tests and fixes for modpow2, muldivmod

This commit is contained in:
OmicronTau 2021-12-05 17:41:22 +03:00 committed by EmelyanenkoK
parent cb31a20206
commit 703bcd6e32
10 changed files with 2017 additions and 54 deletions

View file

@ -264,7 +264,7 @@ class AnyIntView {
return digits[size() - 1];
}
double top_double() const {
return size() > 1 ? (double)digits[size() - 1] + (double)digits[size() - 2] * (1.0 / Tr::Base)
return size() > 1 ? (double)digits[size() - 1] + (double)digits[size() - 2] * Tr::InvBase
: (double)digits[size() - 1];
}
bool is_odd_any() const {
@ -314,8 +314,15 @@ class BigIntG {
digits[0] = x;
}
BigIntG(Normalize, word_t x) : n(1) {
digits[0] = x;
normalize_bool();
if (x >= -Tr::Half && x < Tr::Half) {
digits[0] = x;
} else if (len <= 1) {
digits[0] = x;
normalize_bool();
} else {
digits[0] = ((x + Tr::Half) & (Tr::Base - 1)) - Tr::Half;
digits[n++] = (x >> Tr::word_shift) + (digits[0] < 0);
}
}
BigIntG(const BigIntG& x) : n(x.n) {
std::memcpy(digits, x.digits, n * sizeof(word_t));
@ -757,7 +764,7 @@ bool AnyIntView<Tr>::add_pow2_any(int exponent, int factor) {
while (size() <= k) {
digits[inc_size()] = 0;
}
digits[k] += (factor << dm.rem);
digits[k] += ((word_t)factor << dm.rem);
return true;
}
@ -1087,12 +1094,16 @@ int AnyIntView<Tr>::cmp_any(const AnyIntView<Tr>& yp) const {
template <class Tr>
int AnyIntView<Tr>::cmp_any(word_t y) const {
if (size() > 1) {
return top_word() < 0 ? -1 : 1;
} else if (size() == 1) {
if (size() == 1) {
return digits[0] < y ? -1 : (digits[0] > y ? 1 : 0);
} else {
} else if (!size()) {
return 0x80000000;
} else if (size() == 2 && (y >= Tr::Half || y < -Tr::Half)) {
word_t x0 = digits[0] & (Tr::Base - 1), y0 = y & (Tr::Base - 1);
word_t x1 = digits[1] + (digits[0] >> Tr::word_shift), y1 = (y >> Tr::word_shift);
return x1 < y1 ? -1 : (x1 > y1 ? 1 : (x0 < y0 ? -1 : (x0 > y0 ? 1 : 0)));
} else {
return top_word() < 0 ? -1 : 1;
}
}
@ -1312,17 +1323,14 @@ bool AnyIntView<Tr>::mod_div_any(const AnyIntView<Tr>& yp, AnyIntView<Tr>& quot,
if (k > quot.max_size()) {
return invalidate_bool();
}
quot.set_size(max(k,1));
for(int qi=0; qi< max(k,1); qi++) {
quot.digits[qi]=0;
}
quot.set_size(std::max(k, 1));
quot.digits[0] = 0;
} else {
if (k >= quot.max_size()) {
return invalidate_bool();
}
quot.set_size(k + 1);
double x_top = top_double();
word_t q = std::llrint(x_top * y_inv * Tr::InvBase);
word_t q = std::llrint(top_double() * y_inv * Tr::InvBase);
quot.digits[k] = q;
int i = yp.size() - 1;
word_t hi = 0;
@ -1337,8 +1345,7 @@ bool AnyIntView<Tr>::mod_div_any(const AnyIntView<Tr>& yp, AnyIntView<Tr>& quot,
quot.digits[0] = 0;
}
while (--k >= 0) {
double x_top = top_double();
word_t q = std::llrint(x_top * y_inv);
word_t q = std::llrint(top_double() * y_inv);
quot.digits[k] = q;
for (int i = yp.size() - 1; i >= 0; --i) {
Tr::sub_mul(&digits[k + i + 1], &digits[k + i], q, yp.digits[i]);
@ -1346,15 +1353,18 @@ bool AnyIntView<Tr>::mod_div_any(const AnyIntView<Tr>& yp, AnyIntView<Tr>& quot,
dec_size();
digits[size() - 1] += (digits[size()] << word_shift);
}
if (size() >= yp.size()) {
assert(size() == yp.size());
double x_top = top_double();
double t = x_top * y_inv * Tr::InvBase;
if (size() >= yp.size() - 1) {
assert(size() <= yp.size());
bool grow = (size() < yp.size());
double t = top_double() * y_inv * (grow ? Tr::InvBase * Tr::InvBase : Tr::InvBase);
if (round_mode >= 0) {
t += (round_mode ? 1 : 0.5);
}
word_t q = std::llrint(std::floor(t));
if (q) {
if (grow) {
digits[inc_size()] = 0;
}
for (int i = 0; i < size(); i++) {
digits[i] -= q * yp.digits[i];
}
@ -1411,6 +1421,7 @@ bool AnyIntView<Tr>::mod_div_any(const AnyIntView<Tr>& yp, AnyIntView<Tr>& quot,
return normalize_bool_any();
}
// works for almost-normalized numbers (digits -Base+1 .. Base-1, top non-zero), result also almost-normalized
template <class Tr>
bool AnyIntView<Tr>::mod_pow2_any(int exponent) {
if (!is_valid()) {
@ -1462,25 +1473,21 @@ bool AnyIntView<Tr>::mod_pow2_any(int exponent) {
if (exponent >= max_size() * word_shift) {
return invalidate_bool();
}
if (q - word_shift >= 0) {
if (q - word_shift >= 0) { // original top digit was a non-zero multiple of Base, impossible(?)
digits[size() - 1] = 0;
digits[inc_size()] = ((word_t)1 << (q - word_shift));
}
if (q - word_shift == -1 && size() < max_size() - 1) {
} else if (q - word_shift == -1 && size() < max_size()) {
digits[size() - 1] = -Tr::Half;
digits[inc_size()] = 1;
} else {
digits[size() - 1] = pow;
}
return true;
} else if (v >= Tr::Half) {
if (size() == max_size() - 1) {
return invalidate_bool();
} else {
digits[size() - 1] = v | -Tr::Half;
digits[inc_size()] = ((word_t)1 << (q - word_shift));
return true;
}
} else if (v >= Tr::Half && size() < max_size()) {
word_t w = (((v >> (word_shift - 1)) + 1) >> 1);
digits[size() - 1] = v - (w << word_shift);
digits[inc_size()] = w;
return true;
} else {
digits[size() - 1] = v;
return true;