Skip to content

Instantly share code, notes, and snippets.

@microcai
Created May 30, 2019 08:08
Show Gist options
  • Save microcai/99b95be5a383b281f263dbab97e00911 to your computer and use it in GitHub Desktop.
Save microcai/99b95be5a383b281f263dbab97e00911 to your computer and use it in GitHub Desktop.
templated decimal
#include <string>
namespace Traits{
template<int>
struct ScaleTraits;
template<>
struct ScaleTraits<4>
{
static const int Scale = 10000;
};
}
template<int Digit>
class decimal_templated
{
long long fixed_float;
static const int Scale = Traits::ScaleTraits<Digit>::Scale;
private:
void from_string(const std::string& string_reprent)
{
auto dot_pos = string_reprent.find('.');
if (dot_pos == std::string::npos)
{
fixed_float = Scale * std::strtoll(string_reprent.c_str(), nullptr, 10);
}
else
{
std::string int_part = string_reprent.substr(0, dot_pos);
std::string xiaoshu_part = string_reprent.substr( dot_pos + 1 );
fixed_float = Scale * std::strtoll(int_part.c_str(), nullptr, 10);
// 补齐 tailing 0
if (xiaoshu_part.length() < Digit)
xiaoshu_part.insert(xiaoshu_part.end(), Digit - xiaoshu_part.length(), '0');
fixed_float += std::strtoll(xiaoshu_part.c_str(), nullptr, 10);
}
}
public:
decimal_templated() : fixed_float(0) {}
decimal_templated(int i) : fixed_float(i * Scale) {}
decimal_templated(unsigned i) : fixed_float(i * Scale) {}
decimal_templated(long i) : fixed_float(i * Scale) {}
decimal_templated(unsigned long i) : fixed_float(i * Scale) {}
decimal_templated(float i) : fixed_float( i * Scale + 0.5) {};
decimal_templated(double i) : fixed_float( i * Scale + 0.5) {};
decimal_templated(long double i) : fixed_float( i * Scale + 0.5) {};
decimal_templated(const std::string& string_reprent) { from_string(string_reprent); }
decimal_templated(char string_reprent[]){ from_string(string_reprent); }
public: // io
operator std::string() const // as string
{
auto fixed_float_ = fixed_float;
if (fixed_float_ >= 0)
{
auto int_part = std::to_string( (fixed_float_ / Scale) );
if (fixed_float_ % Scale != 0)
{
std::string xiaoshu_part = std::to_string( (fixed_float_ % Scale) );
if (xiaoshu_part.length() < Digit)
xiaoshu_part.insert(xiaoshu_part.begin(), Digit - xiaoshu_part.length(), '0');
// remove tailing 0
while(*xiaoshu_part.rbegin() == '0')
xiaoshu_part.pop_back();
return int_part + "." + xiaoshu_part;
}
return int_part;
}
else
{
fixed_float_ = - fixed_float;
auto int_part = std::to_string( (fixed_float_ / Scale) );
if (fixed_float_ % Scale != 0)
{
std::string xiaoshu_part = std::to_string( (fixed_float_ % Scale) );
if (xiaoshu_part.length() < Digit)
xiaoshu_part.insert(xiaoshu_part.begin(), Digit - xiaoshu_part.length(), '0');
// remove tailing 0
while(*xiaoshu_part.rbegin() == '0')
xiaoshu_part.pop_back();
return "-" + int_part + "." + xiaoshu_part;
}
return "-" + int_part;
}
}
public: // operations
friend decimal_templated<Digit> operator + (const decimal_templated<Digit>& a, const decimal_templated<Digit>& b)
{
decimal_templated<Digit> r;
r.fixed_float = a.fixed_float + b.fixed_float;
return r;
}
friend decimal_templated<Digit> operator - (const decimal_templated<Digit>& a, const decimal_templated<Digit>& b)
{
decimal_templated<Digit> r;
r.fixed_float = a.fixed_float - b.fixed_float;
return r;
}
friend decimal_templated<Digit> operator * (const decimal_templated<Digit>& a, const decimal_templated<Digit>& b)
{
decimal_templated<Digit> r;
r.fixed_float = a.fixed_float * b.fixed_float / decimal_templated<Digit>::Scale;
return r;
}
friend decimal_templated<Digit> operator / (const decimal_templated<Digit>& a, const decimal_templated<Digit>& b)
{
decimal_templated<Digit> r;
r.fixed_float = a.fixed_float * decimal_templated<Digit>::Scale / b.fixed_float;
return r;
}
friend decimal_templated<Digit> operator % (const decimal_templated<Digit>& a, const decimal_templated<Digit>& b)
{
decimal_templated<Digit> r;
r.fixed_float = a.fixed_float % b.fixed_float;
return r;
}
decimal_templated& operator+= (const decimal_templated& o){ fixed_float += o.fixed_float; return *this; }
decimal_templated& operator-= (const decimal_templated& o){ fixed_float -= o.fixed_float; return *this; }
decimal_templated& operator*= (const decimal_templated& o){ fixed_float = fixed_float * o.fixed_float / Scale; return *this; }
decimal_templated& operator/= (const decimal_templated& o){ fixed_float = fixed_float * Scale / fixed_float; return *this; }
decimal_templated& operator%= (const decimal_templated& o){ fixed_float = fixed_float % fixed_float; return *this; }
};
typedef decimal_templated<4> decimal;
#include <iostream>
int main(int argc, char **argv)
{
decimal a = std::string("2.1");
decimal b = 4;
auto c = a * b;
auto d = a + b;
auto e = a - b;
auto f = b / a;
std::cerr << (std::string) c << std::endl;
std::cerr << (std::string) d << std::endl;
std::cerr << (std::string) e << std::endl;
std::cerr << (std::string) f << std::endl;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment