Last active
September 30, 2023 10:22
-
-
Save Helios-vmg/abd9ef1153c5d43d7a29 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <queue> | |
#include <iomanip> | |
#include <cmath> | |
#include <algorithm> | |
#include <sstream> | |
#include <limits> | |
template <typename Float> | |
struct float_info{}; | |
template <> | |
struct float_info<float>{ | |
typedef unsigned integer_type; | |
static const unsigned bits = 32; | |
static const unsigned exponent_size = 8; | |
static const unsigned exponent_mask = (1 << exponent_size) - 1; | |
static const unsigned mantissa_size = 23; | |
static const integer_type mantissa_mask = ((integer_type)1 << mantissa_size) - 1; | |
static const unsigned exponent_baseline = (1 << (exponent_size - 1)) - 2; | |
}; | |
template <> | |
struct float_info<double>{ | |
typedef unsigned long long integer_type; | |
static const unsigned bits = 64; | |
static const unsigned exponent_size = 11; | |
static const unsigned exponent_mask = (1 << exponent_size) - 1; | |
static const unsigned mantissa_size = 52; | |
static const integer_type mantissa_mask = ((integer_type)1 << mantissa_size) - 1; | |
static const unsigned exponent_baseline = (1 << (exponent_size - 1)) - 2; | |
}; | |
class BigNum{ | |
typedef unsigned char digit; | |
size_t integer_digits; | |
std::deque<digit> number; | |
void reduce(){ | |
while (this->number.size() && this->integer_digits && !this->number.front()){ | |
this->integer_digits--; | |
this->number.pop_front(); | |
} | |
while (this->number.size() && this->number.size() > this->integer_digits && !this->number.back()) | |
this->number.pop_back(); | |
} | |
public: | |
template <typename T> | |
BigNum(T n = 0){ | |
if (!n){ | |
this->integer_digits = 1; | |
this->number.push_back(0); | |
return; | |
} | |
while (n){ | |
this->number.push_front(n % 10); | |
n /= 10; | |
} | |
this->integer_digits = this->number.size(); | |
} | |
template <typename T> | |
static BigNum from_float(T f){ | |
typedef float_info<T> fi; | |
typedef typename fi::integer_type it; | |
static_assert(std::numeric_limits<T>::is_iec559, "We need standard floats."); | |
it y = *(it *)&f; | |
unsigned sign = y >> (fi::bits - 1); | |
int exponent = (y >> (fi::bits - 1 - fi::exponent_size)) & fi::exponent_mask; | |
it mantissa = y & fi::mantissa_mask; | |
BigNum bn((it)mantissa); | |
for (int i = fi::mantissa_size; i--;) | |
bn = bn.half(); | |
if (exponent) | |
bn = bn + BigNum(1); | |
int power = exponent - fi::exponent_baseline; | |
if (exponent) | |
power--; | |
if (power < 0){ | |
power = -power; | |
for (int i = 0; i < power; i++) | |
bn = bn.half(); | |
}else{ | |
for (int i = 0; i < power; i++) | |
bn = bn.times_2(); | |
} | |
return bn; | |
} | |
void print(std::ostream &stream) const{ | |
if (!this->integer_digits) | |
stream << '0'; | |
for (size_t i = 0; i < this->number.size(); i++){ | |
if (i == this->integer_digits) | |
stream << '.'; | |
stream << (int)this->number[i]; | |
} | |
} | |
BigNum half() const{ | |
BigNum ret(0); | |
ret.integer_digits = this->integer_digits; | |
std::deque<digit> &temp = ret.number; | |
for (size_t i = 0; i < this->number.size(); i++){ | |
temp.back() += this->number[i] / 2; | |
temp.push_back(this->number[i] % 2 ? 5 : 0); | |
} | |
ret.reduce(); | |
return ret; | |
} | |
size_t get_integer_digits() const{ | |
return this->integer_digits; | |
} | |
size_t get_fractional_digits() const{ | |
return this->number.size() - this->integer_digits; | |
} | |
digit get_at(int power) const{ | |
if (power >= 0){ | |
if ((size_t)power >= this->integer_digits) | |
return 0; | |
}else{ | |
if ((size_t)-power > this->get_fractional_digits()) | |
return 0; | |
} | |
return this->number[this->integer_digits - power - 1]; | |
} | |
BigNum operator+(const BigNum &b) const{ | |
int max = std::max(this->integer_digits, b.integer_digits); | |
int min = -(int)std::max(this->get_fractional_digits(), b.get_fractional_digits()); | |
std::vector<digit> temp; | |
temp.reserve(max + 1 - min); | |
temp.push_back(0); | |
for (int i = min; i < max; i++){ | |
digit x = this->get_at(i) + b.get_at(i); | |
temp.back() += x % 10; | |
temp.push_back(x / 10); | |
} | |
BigNum ret(0); | |
ret.integer_digits = temp.size() + min; | |
ret.number.clear(); | |
for (size_t i = 0; i < temp.size(); i++) | |
ret.number.push_front(temp[i]); | |
ret.reduce(); | |
return ret; | |
} | |
BigNum times_2() const{ | |
return *this + *this; | |
} | |
}; | |
std::ostream &operator<<(std::ostream &stream, const BigNum &bn){ | |
bn.print(stream); | |
return stream; | |
} | |
int main(){ | |
while (true){ | |
double input; | |
std::cin >> input; | |
if (!std::cin) | |
break; | |
BigNum bn = BigNum::from_float(input); | |
std::cout << bn << " - " << bn.get_fractional_digits() << std::endl; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment