/*
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 .
Copyright 2017-2019 Telegram Systems LLP
*/
#pragma once
#include "common/refint.h"
namespace td {
class NegExpBinTable {
int precision, maxpw2, minpw2;
std::vector exp_pw2_table; // table of 2^precision * exp(- 2^k) for k = max_pw2-1 .. min_pw2
std::vector exp_pw2_ref_table; // same data
td::BigInt256 One;
public:
NegExpBinTable(int _precision, int _maxpw2, int _minpw2) : precision(255), maxpw2(_maxpw2), minpw2(_minpw2) {
(_precision > 0 && _precision < 256 && _minpw2 <= 0 && _maxpw2 > 0 && _maxpw2 <= 256 && _minpw2 >= -256 && init() &&
adjust_precision(_precision)) ||
invalidate();
}
bool is_valid() const {
return minpw2 < maxpw2;
}
int get_precision() const {
return precision;
}
int get_exponent_precision() const {
return -minpw2;
}
int get_exponent_max_log2() const {
return maxpw2;
}
const td::BigInt256* exp_pw2(int k) const { // returns 2^precision * exp(-2^k) or null
return (k >= minpw2 && k < maxpw2) ? &exp_pw2_table[k - minpw2] : nullptr;
}
td::RefInt256 exp_pw2_ref(int k) const {
if (k >= minpw2 && k < maxpw2) {
return exp_pw2_ref_table[k - minpw2];
} else {
return {};
}
}
bool nexpf(td::BigInt256& res, long long x, int k) const; // res := 2^precision * exp(-x * 2^k)
td::RefInt256 nexpf(long long x, int k) const;
private:
bool init();
bool init_one();
bool adjust_precision(int new_precision, int rmode = 0);
bool invalidate() {
minpw2 = maxpw2 = 0;
return false;
}
td::BigInt256 series_exp(int k) const; // returns 2^precision * exp(-2^(-k)), k >= 0
};
struct SuperFloat {
struct SetZero {};
struct SetOne {};
struct SetNan {};
td::uint128 m;
int s;
SuperFloat() = default;
SuperFloat(SetZero) : m(0, 0), s(0) {
}
SuperFloat(SetOne) : m(0, 1), s(0) {
}
SuperFloat(SetNan) : m(0, 0), s(std::numeric_limits::min()) {
}
SuperFloat(td::uint128 _m, int _s = 0) : m(_m), s(_s) {
}
SuperFloat(td::uint64 _m, int _s = 0) : m(0, _m), s(_s) {
}
explicit SuperFloat(BigInt256 x);
static SuperFloat Zero() {
return SetZero{};
}
static SuperFloat One() {
return SetOne{};
}
static SuperFloat NaN() {
return SetNan{};
}
void set_zero() {
m = td::uint128(0, 0);
s = 0;
}
void set_one() {
m = td::uint128(0, 1);
s = 0;
}
void set_nan() {
s = std::numeric_limits::min();
}
bool is_nan() const {
return s == std::numeric_limits::min();
}
bool is_zero() const {
return m.is_zero();
}
bool normalize();
td::uint64 top() const {
return m.rounded_hi();
}
static td::uint128 as_uint128(const td::BigInt256& x);
static td::uint64 as_uint64(const td::BigInt256& x);
};
class NegExpInt64Table {
enum { max_exp = 45 };
unsigned char table0_shift[max_exp + 1];
td::uint64 table0[max_exp + 1], table1[256], table2[256];
public:
NegExpInt64Table();
// compute x * exp(-k / 2^16);
// more precisely: computes 0 <= y <= x for 0 <= x < 2^60, s.that |y - x * exp(-k / 2^16)| < 1
// two different implementations of this functions would return values differing by at most one
td::uint64 umulnexps32(td::uint64 x, unsigned k, bool trunc = false) const;
td::int64 mulnexps32(td::int64 x, unsigned k, bool trunc = false) const;
static const NegExpInt64Table& table();
private:
};
td::uint64 umulnexps32(td::uint64 x, unsigned k, bool trunc = false); // compute x * exp(-k / 2^16)
td::int64 mulnexps32(td::int64 x, unsigned k, bool trunc = false);
} // namespace td