Skip to content

Instantly share code, notes, and snippets.

@Helios-vmg
Last active September 30, 2023 10:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Helios-vmg/abd9ef1153c5d43d7a29 to your computer and use it in GitHub Desktop.
Save Helios-vmg/abd9ef1153c5d43d7a29 to your computer and use it in GitHub Desktop.
#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