1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-02-15 04:32:21 +00:00
ton/crypto/test/test-cells.cpp
ton 13140ddf29 updated block header
1. Updated block header, proofs now contain more data
   Notice, that old proofs may become invalid in the future
2. Fixed message routing
3. Fixed block creator id in block header
4. Support for full proofs in tonlib
5. Support for partial state download
6. Some other bugfixes
2019-09-18 21:46:32 +04:00

656 lines
23 KiB
C++

/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
*/
#include <algorithm>
#include <string>
#include <vector>
#include <iostream>
#include <sstream>
#include <memory>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include "common/refcnt.hpp"
#include "common/bigint.hpp"
#include "common/refint.h"
#include "common/bigexp.h"
#include "common/bitstring.h"
#include "common/util.h"
#include "vm/cells.h"
#include "vm/cellslice.h"
#include "td/utils/tests.h"
#include "td/utils/crypto.h"
#include "td/utils/misc.h"
static std::stringstream create_ss() {
std::stringstream ss;
ss.imbue(std::locale::classic());
ss.setf(std::ios_base::fixed, std::ios_base::floatfield);
ss.precision(6);
return ss;
}
static std::stringstream os = create_ss();
void show_total_cells(std::ostream& stream) {
stream << "total cells = " << vm::DataCell::get_total_data_cells() << std::endl;
}
TEST(Cells, simple) {
os = create_ss();
using namespace td::literals;
vm::CellBuilder cb1, cb2;
cb1.store_bytes("Hello, ", 7).reserve_slice(48) = td::BitSlice{(const unsigned char*)"world!", 48};
cb2.store_bits(td::BitSlice{(const unsigned char*)"\xd0", 4})
.store_long(17239, 16)
.store_long(-17, 11)
.store_long(1000000239, 32)
.store_long(1000000239LL * 1000000239)
.store_int256("-1000000000000000000000000239"_i256, 91);
cb1.store_ref(cb2.finalize_copy());
show_total_cells(os);
cb2.store_bytes("<->", 3);
td::Ref<vm::DataCell> c1{cb1.finalize_copy()}, c2{cb2.finalize_copy()};
unsigned char hbuff[vm::Cell::hash_bytes];
os << "cb1 = " << cb1 << "; hash=" << td::buffer_to_hex(td::Slice(cb1.compute_hash(hbuff), 32)) << "; c1 = " << *c1
<< std::endl;
os << "cb2 = " << cb2 << "; hash=" << td::buffer_to_hex(td::Slice(cb2.compute_hash(hbuff), 32)) << "; c2 = " << *c2
<< std::endl;
show_total_cells(os);
vm::CellSlice cr1(c1);
cr1.dump(os);
os << "fetch_octet() = " << cr1.fetch_octet() << std::endl;
cr1.dump(os);
os << "fetch_octet() = " << cr1.fetch_octet() << std::endl;
cr1.dump(os);
os << "fetch_octet() = " << cr1.fetch_octet() << std::endl;
cr1.dump(os);
os << "fetch_octet() = " << cr1.fetch_octet() << std::endl;
cr1.dump(os);
os << "fetch_ref()=" << td::buffer_to_hex(cr1.prefetch_ref()->get_hash().as_slice()) << std::endl;
vm::CellSlice cr(vm::NoVm(), cr1.fetch_ref());
cr.dump(os);
os << "prefetch_ulong(4)=" << cr.prefetch_ulong(4) << std::endl;
cr.dump(os);
os << "fetch_ulong(4)=" << cr.fetch_ulong(4) << std::endl;
cr.dump(os);
os << "fetch_long(16)=" << cr.fetch_long(16) << std::endl;
cr.dump(os);
os << "prefetch_long(11)=" << cr.prefetch_long(11) << std::endl;
cr.dump(os);
os << "fetch_int256(11)=" << cr.fetch_int256(11) << std::endl;
cr.dump(os);
os << "fetch_long(32)=" << cr.fetch_long(32) << std::endl;
cr.dump(os);
os << "prefetch_long(64)=" << cr.prefetch_long(64) << std::endl;
cr.dump(os);
os << "fetch_long(64)=" << cr.fetch_long(64) << std::endl;
cr.dump(os);
os << "prefetch_int256(91)=" << cr.prefetch_int256(91) << std::endl;
cr.dump(os);
os << "fetch_int256(91)=" << cr.fetch_int256(91) << std::endl;
cr.dump(os);
os << "fetch_long(24)=" << cr.fetch_long(24) << std::endl;
cr.dump(os);
cr.clear();
REGRESSION_VERIFY(os.str());
}
void test_two_bitstrings(const td::BitSlice& bs1, const td::BitSlice& bs2) {
using td::to_binary;
using td::to_hex;
os << "bs1 = " << bs1.to_binary() << " = " << bs1.to_hex() << std::endl;
os << "bs2 = " << to_binary(bs2) << " = " << to_hex(bs2) << std::endl;
td::BitString st{bs1};
//td::BitString st;
//st.append(bs1);
os << "st = " << to_binary(st) << " = " << to_hex(st) << std::endl;
st.append(bs2);
os << "st = " << to_binary(st) << " = " << to_hex(st) << std::endl;
ASSERT_EQ(to_binary(st), to_binary(bs1) + to_binary(bs2));
auto bs3 = st.subslice(bs1.size(), bs2.size());
os << "bs3 = " << to_binary(bs3) << " = " << to_hex(bs3) << std::endl;
ASSERT_EQ(to_binary(bs3), to_binary(bs2));
ASSERT_EQ(to_hex(bs3), to_hex(bs2));
bs1.dump(os);
bs2.dump(os);
bs3.dump(os);
std::string bs2_bin = to_binary(bs2);
for (unsigned i = 0; i <= bs2.size(); i++) {
for (unsigned j = 0; j <= bs2.size() - i; j++) {
auto bs4 = bs2.subslice(i, j);
auto bs5 = bs3.subslice(i, j);
if (!(to_binary(bs4) == to_binary(bs5) && to_hex(bs4) == to_hex(bs5) && to_binary(bs4) == bs2_bin.substr(i, j))) {
bs4.dump(os);
bs5.dump(os);
os << "bs2.subslice(" << i << ", " << j << ") = " << to_binary(bs4) << " = " << to_hex(bs4) << std::endl;
os << "bs3.subslice(" << i << ", " << j << ") = " << to_binary(bs5) << " = " << to_hex(bs5) << std::endl;
}
ASSERT_EQ(to_binary(bs4), to_binary(bs5));
ASSERT_EQ(to_hex(bs4), to_hex(bs5));
ASSERT_EQ(to_binary(bs4), bs2_bin.substr(i, j));
}
}
}
void test_one_bitstring(const td::BitSlice& bs) {
std::string bs_bin = bs.to_binary();
for (unsigned i1 = 0; i1 <= bs.size(); i1++) {
for (unsigned j1 = 0; j1 <= bs.size() - i1; j1++) {
auto bs1 = bs.subslice(i1, j1);
ASSERT_EQ(bs1.to_binary(), bs_bin.substr(i1, j1));
for (unsigned i2 = 0; i2 <= bs.size() && i2 < 8; i2++) {
for (unsigned j2 = 0; j2 <= bs.size() - i2; j2++) {
os << "(" << i1 << "," << j1 << ")+(" << i2 << "," << j2 << ")" << std::endl;
auto bs2 = bs.subslice(i2, j2);
ASSERT_EQ(bs2.to_binary(), bs_bin.substr(i2, j2));
test_two_bitstrings(bs1, bs2);
}
}
}
}
}
void test_bitstring_fill(unsigned n, unsigned p, unsigned k) {
td::BitString bs{n * 2};
std::string s;
auto sl1 = td::BitSlice{(const unsigned char*)"\x40", 2};
for (unsigned i = 0; i < n; i++) {
bs.append(sl1);
s += "01";
}
os << td::to_binary(bs) << " = " << td::to_hex(bs) << std::endl;
ASSERT_EQ(td::to_binary(bs), s);
unsigned q = k %= p;
for (unsigned i = 0; i < p; i++) {
unsigned a = (q * n * 2) / p;
unsigned b = ((q + 1) * n * 2) / p;
bs.subslice_write(a, b - a) = (q & 1);
std::fill(s.begin() + a, s.begin() + b, (q & 1) + '0');
os << "Step " << i << " (" << a << "," << b << "): " << td::to_binary(bs) << " = " << td::to_hex(bs) << std::endl;
ASSERT_EQ(td::to_binary(bs), s);
q = (q + k) % p;
}
bs.subslice_write(4, 16) = td::BitSlice{(const unsigned char*)"\x69\x96", 16};
os << td::to_binary(bs) << " = " << td::to_hex(bs) << std::endl;
std::string t = "0110100110010110";
std::copy(t.begin(), t.end(), s.begin() + 4);
ASSERT_EQ(td::to_binary(bs), s);
}
TEST(Bitstrings, main) {
os = create_ss();
auto test = td::BitSlice{(const unsigned char*)"test", 32};
ASSERT_EQ(test.to_hex(), "74657374");
test_two_bitstrings({(const unsigned char*)"\xf1\xd0", 12}, test);
test_two_bitstrings({(const unsigned char*)"\x9f", 3}, {(const unsigned char*)"t", 3});
test_bitstring_fill(17 * 3, 17, 4);
//test_one_bitstring({(const unsigned char*)"SuperTest", 72});
REGRESSION_VERIFY(os.str());
}
void test_parse_dec(std::string s) {
td::BigInt256 x, y;
os << "s=\"" << s << "\"" << std::endl;
x.parse_dec_slow(s);
y.parse_dec(s);
x.dump(os);
y.dump(os);
ASSERT_TRUE(x == y);
std::string s1 = x.to_dec_string();
os << s1 << std::endl;
ASSERT_EQ(s, s1);
std::string s2 = x.to_hex_string();
os << s2 << std::endl;
std::string s3 = x.to_hex_string_slow();
os << s3 << std::endl;
ASSERT_EQ(s2, s3);
}
void test_pow2(int exponent) {
td::BigInt256 x;
x.set_pow2(exponent);
os << "2^" << exponent << " = " << x.to_dec_string() << " = 0x" << x.to_hex_string() << std::endl;
x.dump(os);
}
void test_fits(const td::BigInt256& x) {
int m = 0, n = 0;
const int limit = 300;
os << "x=" << x.to_dec_string() << "; log2(|x|)=" << std::log2(std::abs(x.to_double())) << std::endl;
x.dump(os);
while (m < limit && !x.unsigned_fits_bits(m)) {
m++;
}
for (int i = m; i < limit; i++) {
ASSERT_TRUE(x.unsigned_fits_bits(i));
}
int su = x.bit_size(false);
while (n < limit && !x.signed_fits_bits(n)) {
n++;
}
for (int i = n; i < limit; i++) {
ASSERT_TRUE(x.signed_fits_bits(i));
}
int ss = x.bit_size();
os << "x=" << x.to_dec_string() << "=0x" << x.to_hex_string() << "; x=" << x.to_double()
<< "; log2(|x|)=" << std::log2(std::abs(x.to_double())) << "; unsigned: " << m << "=" << su
<< " bits; signed: " << n << "=" << ss << " bits" << std::endl;
ASSERT_TRUE(su == m || (su == 0x7fffffff && m == limit));
ASSERT_EQ(ss, n);
ASSERT_EQ(x.to_hex_string(), x.to_hex_string_slow());
td::BigInt256 y, z;
ASSERT_TRUE(y.parse_hex(x.to_hex_string()) && y == x);
ASSERT_TRUE(z.parse_dec(x.to_dec_string()) && z == x);
}
void test_divmod(const td::BigInt256& x, const td::BigInt256& y) {
td::BigInt256 q, r(x);
os << "x = " << x << " = ";
x.dump(os);
os << "y = " << y << " = ";
y.dump(os);
if (!r.mod_div_bool(y, q)) {
os << "division error!\n";
ASSERT_TRUE(0);
} else {
q.dump(os);
r.dump(os);
if (!q.normalize_bool() || !r.normalize_bool()) {
os << "cannot normalize q or r!\n";
ASSERT_TRUE(0);
} else {
os << "q = " << q << "; r = " << r << std::endl;
if (y.sgn() > 0) {
ASSERT_TRUE(r.sgn() >= 0);
ASSERT_TRUE(r.cmp(y) < 0);
} else {
ASSERT_TRUE(r.sgn() <= 0);
ASSERT_TRUE(r.cmp(y) > 0);
}
r.add_mul(q, y);
ASSERT_TRUE(r.normalize() == x);
}
}
}
void test_export_int(const td::BigInt256& x, bool sgnd = true) {
os << "x = " << x.to_hex_string() << std::endl;
int bad = 0, ok = 0;
for (int i = 1; i <= 33; i++) {
unsigned char buff[33];
std::memset(buff, 0xcc, sizeof(buff));
if (!x.export_bytes(buff, i, sgnd)) {
ASSERT_EQ(bad, i - 1);
bad = i;
continue;
} else if (++ok < 5) {
if (bad == i - 1) {
os << "export(" << bad << ", " << sgnd << ") = (bad)" << std::endl;
}
os << "export(" << i << ", " << sgnd << ") =";
char tmp[33 * 3 + 1];
for (int j = 0; j < i; j++) {
sprintf(tmp + 3 * j, " %02x", buff[j]);
}
os << tmp << std::endl;
td::BigInt256 y;
ASSERT_TRUE(y.import_bytes(buff, i, sgnd));
os << "import() = " << y.to_hex_string() << std::endl;
ASSERT_TRUE(!x.cmp_un(y));
}
}
if (!ok) {
os << "export(" << bad << ", " << sgnd << ") = (bad)" << std::endl;
}
}
TEST(Bigint, main) {
os = create_ss();
using namespace td::literals;
td::BigInt256 x, y, z;
test_parse_dec("0");
test_parse_dec("1");
test_parse_dec("-1");
test_parse_dec("123");
test_parse_dec("-239");
test_parse_dec("-115792089237316195423570985008687907853269984665640564039457584007913129639936");
test_parse_dec("115792089237316195423570985008687907853269984665640564039457584007913129639935");
test_parse_dec("143126893554044595713052252685501316785002612509329899766666973726012466208042");
test_parse_dec("100000000000000000000000000000000000000000000000000000000000000000000000000001");
x.parse_dec("11111111111111111111111111111111111111111111111111111111111111111111111111111");
y.parse_dec("22222222222222222222222222222222222");
x += y;
os << x.to_dec_string() << std::endl;
x -= y;
os << x.to_dec_string() << std::endl;
x -= y;
os << x.to_dec_string() << std::endl;
y -= x;
os << y.to_dec_string() << std::endl;
y += x;
os << x.to_dec_string() << std::endl;
x.parse_dec("10000000000000000000000000000001");
y.parse_dec("11111111111111111111111111111111");
z.add_mul(x, y);
os << x.to_dec_string() << " * " << y.to_dec_string() << " = " << z.to_dec_string() << std::endl;
test_pow2(0);
test_pow2(1);
test_pow2(54);
test_pow2(55);
test_pow2(56);
test_pow2(57);
test_pow2(4 * 56 - 2);
test_pow2(4 * 56 - 1);
test_pow2(4 * 56);
test_pow2(4 * 56 + 1);
test_pow2(255);
test_pow2(256);
test_fits("1111111111111111111111111111"_i256);
test_fits(
"0000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffff"_x256);
for (int i = 10; i >= -10; --i) {
test_fits(td::BigInt256(i));
}
test_export_int("10000000000000000000000000000000000000"_i256);
for (int k = 127; k <= 129; k++) {
x.set_pow2(k).add_tiny(-1);
test_export_int(x, true);
test_export_int(x, false);
x.add_tiny(1);
test_export_int(x, true);
test_export_int(x, false);
x.add_tiny(1);
test_export_int(x, true);
test_export_int(x, false);
x.negate();
test_export_int(x, true);
test_export_int(x, false);
x.add_tiny(1);
test_export_int(x, true);
test_export_int(x, false);
x.add_tiny(1);
test_export_int(x, true);
test_export_int(x, false);
}
for (x = 1, y.set_pow2(256).divmod_tiny(3); x.cmp(y) < 0; x.mul_tiny(3).normalize()) {
test_export_int(x, true);
x.negate();
test_export_int(x, true);
x.negate();
}
test_export_int("7fffffffffffffffffffffffffffffff"_x256);
test_export_int("ffffffffffffffffffffffffffffffff"_x256);
test_export_int("7fffffffffffffffffffffffffffffff"_x256);
test_export_int("ffffffffffffffffffffffffffffffff"_x256);
for (int i = 0; i <= 257; i++) {
x.set_pow2(i).add_tiny(-3);
for (int j = -3; j <= 3; j++) {
x.negate().normalize();
os << "-2^" << i << "+" << -j << ": ";
test_fits(x);
x.negate().normalize();
os << "2^" << i << "+" << j << ": ";
test_fits(x);
x.add_tiny(1);
}
}
for (auto t : {"fffffffffffffffffffffffffffffffffffffff"_x256, td::BigInt256{-1},
"123456789abcdef0123456789abcdef0123456789abcdef"_x256, "-8000000000000000000000000001"_x256}) {
for (int i = 0; i <= 256; i++) {
(x = t).mod_pow2(i).dump(os);
os << "mod 2^" << i << " : " << x.to_hex_string() << std::endl;
}
}
test_divmod(x.set_pow2(224), "10000000000000"_i256);
test_divmod(x.set_pow2(256), "100000000000000000000000000000000000000000"_i256);
test_divmod(x.set_pow2(256), "100000000000000000000000000000000000000000000"_i256);
test_divmod(x.set_pow2(80), "-100000000000000000000000000000000000000000000"_i256);
test_divmod(x.set_pow2(256), y.set_pow2(128).add_tiny(-1));
test_divmod(x.set_pow2(224), y.set_pow2(112).add_tiny(-1));
test_divmod(x.set_pow2(222), y.set_pow2(111).add_tiny(-1));
test_divmod(td::BigInt256(-1), y.set_pow2(256));
test_divmod("10000000000000000000000000000000000000000000000000000000000000000"_i256,
"142857142857142857142857142857142857"_i256);
test_divmod("100000000"_i256, "-253"_i256);
test_divmod("-100000000"_i256, "-253"_i256);
test_divmod("-100000000"_i256, "253"_i256);
test_divmod(x.set_pow2(222), td::BigInt256{std::numeric_limits<td::BigInt256::word_t>::min()});
test_divmod(x.set_pow2(222).negate(), td::BigInt256{std::numeric_limits<td::BigInt256::word_t>::min()});
REGRESSION_VERIFY(os.str());
}
TEST(RefInt, main) {
os = create_ss();
using namespace td::literals;
auto x = "10000000000000000000000"_ri256;
td::RefInt256 y{true, -239}, z{false};
auto v = x + y;
std::move(v);
os << x << " + " << y << " = " << x + y << std::endl;
os << x << " - " << y << " = " << x - y << std::endl;
os << x << " * " << y << " = " << x * y << std::endl;
os << x << " / " << y << " = " << x / y << std::endl;
os << x << " % " << y << " = " << x % y << std::endl;
os << x << " + " << y << " = " << x + y << std::endl;
os << "10000000000000000000000000000000000000000"_ri256 / "27182818284590"_ri256 << std::endl;
{
auto w(x + y);
z = w;
}
os << "(x-y)*(x+y) = " << (x - y) * (x + y) << std::endl;
os << "z = " << z << std::endl;
z = x;
x += y;
os << "new x = " << x << " = 0x" << hex_string(x) << std::endl;
os << "z = (old x) = " << std::move(z) << std::endl;
os << "x + y = " << std::move(x) + std::move(y) << std::endl;
z = "10000000000000000000000000000000000000000000000000000000000000000000000"_ri256;
//z = td::RefInt256{true}
//z.unique_write()->set_pow2(256);
x = td::RefInt256{true, 0};
int i = 1;
while (z->sgn() > 0) {
x += z;
z.write().add_tiny(i >> 1).divmod_tiny(i);
++i;
}
x.write().normalize();
os << x << " = " << hex_string(x) << std::endl;
REGRESSION_VERIFY(os.str());
}
TEST(crc16, main) {
os = create_ss();
std::string s = "EMSI_FCK";
unsigned crc16 = td::crc16(td::Slice{s});
os << "s = `" << s << "`; crc16 = " << std::hex << crc16 << std::dec << std::endl;
REGRESSION_VERIFY(os.str());
}
TEST(base64, main) {
os = create_ss();
std::vector<std::string> arr = {"TEST STRING NUMBER ONE", "TEST STRING NUMBER FOUR", "TEST STRING NUMBER THREE"};
for (std::string s : arr) {
std::string t = td::str_base64_encode(s);
std::string u = td::str_base64_decode(t);
os << "`" << s << "` -> `" << t << "` -> `" << u << "`" << std::endl;
os << (s == u) << std::endl;
}
std::string s;
int k = 0;
for (int i = 0; i < 1024; i++) {
s.push_back((char)(k >> 8));
k = 69069 * k + 1;
}
std::string t = td::str_base64_encode(s);
std::string u = td::str_base64_decode(t, true);
os << t << std::endl;
os << (s == u) << std::endl;
t = td::str_base64_encode(s, true);
u = td::str_base64_decode(t, true);
os << t << std::endl;
os << (s == u) << std::endl;
u = td::sha256(td::Slice{s});
for (int i = 0; i < 32; i++) {
os << std::hex << ((u[i] >> 4) & 15) << (u[i] & 15);
}
os << std::dec << std::endl;
REGRESSION_VERIFY(os.str());
}
void check_bits256_scan(std::ostream& stream, td::Bits256 a, td::Bits256 b) {
auto c = a ^ b;
auto bit = c.count_leading_zeroes();
auto bit2 = a.count_matching(b);
// stream << a.to_hex() << " and " << b.to_hex() << " match in " << bit << " or " << bit2 << " first bits" << std::endl;
// std::cerr << a.to_hex() << " and " << b.to_hex() << " match in " << bit << " or " << bit2 << " first bits (a XOR b = " << c.to_hex() << ")" << std::endl;
CHECK((int)bit >= 0 && bit <= 256);
for (td::uint32 i = 0; i < bit; i++) {
CHECK(a[i] == b[i]);
}
CHECK(bit == 256 || a[bit] != b[bit]);
CHECK(bit == bit2);
}
void check_bits_scan(std::ostream& stream, td::ConstBitPtr a, bool value) {
auto bit = (unsigned)a.scan(value, 256);
CHECK((int)bit >= 0 && bit <= 256);
for (td::uint32 i = 0; i < bit; i++) {
CHECK(a[i] == value);
}
CHECK(bit == 256 || a[bit] != value);
}
TEST(bits256_scan, main) {
os = create_ss();
td::Bits256 a, b;
int k = 0;
unsigned char r[1024];
for (auto& c : r) {
c = (k & 0x80) ? (unsigned char)(k >> 8) : 0;
k = 69069 * k + 1;
}
for (k = 0; k < 32; k++) {
a = td::ConstBitPtr{r + 32 * k};
for (int j = 0; j < 32; j++) {
b = td::ConstBitPtr{r + 32 * j};
check_bits256_scan(os, a, b);
}
b = a;
unsigned i = r[7 + k];
b[i] = b[i] ^ true;
check_bits256_scan(os, a, b);
}
for (k = 0; k < 256; k++) {
check_bits_scan(os, td::ConstBitPtr{r} + k, false);
check_bits_scan(os, td::ConstBitPtr{r} + k, true);
}
os << "bits256_scan test OK";
REGRESSION_VERIFY(os.str());
}
bool check_exp(std::ostream& stream, const td::NegExpBinTable& tab, double x) {
long long xx = lround(x * (1LL << 52));
td::BigInt256 yy;
if (!tab.nexpf(yy, -xx, 52)) {
stream << "cannot compute exp(" << x << ") = exp(" << xx << " * 2^(-52))" << std::endl;
return false;
}
double y = yy.to_double() * exp2(-252);
double y0 = exp(x);
bool ok = (abs(y - y0) < 1e-15);
if (!ok) {
stream << "exp(" << x << ") = exp(" << xx << " * 2^(-52)) = " << yy << " / 2^252 = " << y << " (correct value is "
<< y0 << ") " << (ok ? "match" : "incorrect") << std::endl;
}
return ok;
}
TEST(bigexp, main) {
os = create_ss();
td::NegExpBinTable tab(252, 32, -128);
bool ok = true;
if (!tab.is_valid()) {
os << "cannot initialize td::NegExpBinTable(252, 32, -128)" << std::endl;
ok = false;
} else {
// for (int i = -128; i < 32; i++) {
// os << "exp(-2^" << i << ") = " << tab.exp_pw2_ref(i) << " / 2^252 = " << tab.exp_pw2_ref(i)->to_double() * exp2(-252) << " (correct value is " << exp(-exp2(i)) << ")" << std::endl;
// }
ok &= check_exp(os, tab, -2.39);
ok &= check_exp(os, tab, 0);
ok &= check_exp(os, tab, -1);
ok &= check_exp(os, tab, -2);
ok &= check_exp(os, tab, -16);
ok &= check_exp(os, tab, -17);
ok &= check_exp(os, tab, -0.5);
ok &= check_exp(os, tab, -0.25);
ok &= check_exp(os, tab, -3.1415926535);
ok &= check_exp(os, tab, -1e-9);
}
if (ok) {
os << "bigexp test OK\n";
} else {
os << "bigexp test FAILED\n";
}
REGRESSION_VERIFY(os.str());
}
bool check_intexp(std::ostream& stream, td::uint64 x, unsigned k, td::uint64 yc = 0) {
td::uint64 y = td::umulnexps32(x, k);
long long delta = (long long)(y - yc);
bool ok = (y <= x && std::abs(delta) <= 1);
if (!ok) {
stream << x << "*exp(-" << k << "/65536) = " << y << " (correct value " << yc << ", delta = " << delta << ")"
<< std::endl;
}
return ok;
}
TEST(uint64_exp, main) {
os = create_ss();
bool ok = true;
ok &= check_intexp(os, 3167801306015831286, 4003, 2980099890648636481);
ok &= check_intexp(os, 1583900653007915643, 4003, 1490049945324318240);
ok &= check_intexp(os, 9094494907266047891, 17239, 6990995826652297465);
ok &= check_intexp(os, 5487867407433215099, 239017, 143048684491504152);
ok &= check_intexp(os, 46462010749955243, 239017, 1211095134625318); // up
ok &= check_intexp(os, 390263500024095125, 2700001, 1);
ok &= check_intexp(os, 390263500024095124, 2700001, 1);
ok &= check_intexp(os, std::numeric_limits<td::uint64>::max(), 2952601, 1);
ok &= check_intexp(os, std::numeric_limits<td::uint64>::max(), 2952696, 1);
ok &= check_intexp(os, std::numeric_limits<td::uint64>::max(), 2952697, 0);
ok &= check_intexp(os, std::numeric_limits<td::uint64>::max(), 2952800, 0);
ok &= check_intexp(os, std::numeric_limits<td::uint64>::max(), 295269700, 0);
ok &= check_intexp(os, std::numeric_limits<td::uint64>::max(), 2000018, 1028453);
ok &= check_intexp(os, 1ULL << 60, 2770991, 1);
ok &= check_intexp(os, 1ULL << 60, 2770992, 0);
if (ok) {
os << "uint64_exp test OK\n";
} else {
os << "uint64_exp test FAILED\n";
}
REGRESSION_VERIFY(os.str());
}