Last active
October 18, 2020 21:39
-
-
Save arthurmco/26bfc94981096ea98878b3a32324f1e1 to your computer and use it in GitHub Desktop.
A small file with an example of fixed-point decimal arithmetic in c++
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
// DecimalMode.cpp : This file contains the 'main' function. Program execution begins and ends there. | |
// | |
#include <iostream> | |
// a constexpr power of 10 function | |
constexpr double pow10(int decs) { | |
if (decs >= 0) { | |
double v = 1; | |
for (auto i = 0; i < decs; i++) { | |
v *= 10; | |
} | |
return v; | |
} | |
else if (decs < 0) { | |
double v = 1; | |
for (auto i = 0; i > decs; i--) { | |
v /= 10.0; | |
} | |
return v; | |
} | |
} | |
/** | |
* A fixed point decimal type for C++ | |
* | |
* Might be integrated in Familyline when it is production-ready | |
* | |
* Be careful that calculations with a big number of decimals (like, hum, 9) | |
* can overflow. | |
*/ | |
template <int decimals> | |
class decimal { | |
private: | |
long long value_ = 0; | |
static constexpr double mul_ = pow10(decimals); | |
static constexpr double div_ = pow10(-decimals); | |
public: | |
decimal() | |
: decimal(0) | |
{} | |
decimal(int val) | |
: value_(val * mul_) | |
{} | |
decimal(double val) | |
: value_(val* mul_) | |
{} | |
decimal(const decimal& d) { | |
this->value_ = d.value_; | |
} | |
double val() const { | |
return double(value_) * div_; | |
} | |
decimal& operator=(const decimal& d) { | |
this->value_ = d.value_; | |
return *this; | |
} | |
decimal operator+(const decimal& d) { | |
decimal r; | |
r.value_ = this->value_ + d.value_; | |
return r; | |
} | |
decimal operator-(const decimal& d) { | |
decimal r; | |
r.value_ = this->value_ - d.value_; | |
return r; | |
} | |
decimal operator*(const decimal& d) { | |
decimal r; | |
unsigned long long pureval = this->value_ * d.value_; | |
r.value_ = pureval * this->div_; | |
return r; | |
} | |
decimal operator/(const decimal& d) { | |
decimal r; | |
unsigned long long quo = this->value_ / d.value_; | |
unsigned long long rem = this->value_ % d.value_; | |
// Do the division like you would do on paper: | |
// continue dividing the remainder and add a decimal house more or less | |
r.value_ = (quo * this->mul_) + ((rem * this->mul_) / d.value_); | |
return r; | |
} | |
decimal& operator+=(const decimal& d) { | |
*this = *this + d; | |
return *this; | |
} | |
decimal& operator-=(const decimal& d) { | |
*this = *this - d; | |
return *this; | |
} | |
decimal& operator*=(const decimal& d) { | |
*this = *this * d; | |
return *this; | |
} | |
decimal& operator/=(const decimal& d) { | |
*this = *this / d; | |
return *this; | |
} | |
decimal operator-() { | |
decimal r; | |
r.value_ = -this->value_; | |
return r; | |
} | |
decimal operator+(int v) { | |
return *this + decimal{ v }; | |
} | |
decimal operator-(int v) { | |
return *this - decimal{ v }; | |
} | |
decimal operator*(int v) { | |
return *this * decimal{ v }; | |
} | |
decimal operator/(int v) { | |
return *this / decimal{ v }; | |
} | |
decimal operator+(double v) { | |
return *this + decimal{ v }; | |
} | |
decimal operator-(double v) { | |
return *this - decimal{ v }; | |
} | |
decimal operator*(double v) { | |
return *this * decimal{ v }; | |
} | |
decimal operator/(double v) { | |
return *this / decimal{ v }; | |
} | |
decimal& operator+=(double v) { | |
return *this += decimal{ v }; | |
} | |
decimal& operator-=(double v) { | |
return *this -= decimal{ v }; | |
} | |
decimal& operator*=(double v) { | |
return *this *= decimal{ v }; | |
} | |
decimal& operator/=(double v) { | |
return *this /= decimal{ v }; | |
} | |
}; | |
template <int v> | |
void print_decimal() { | |
decimal<v> d1 = 20.5; | |
decimal<v> d2 = 30.5; | |
decimal<v> d3 = d1 + d2; | |
decimal<v> d4 = d2 - d1; | |
decimal<v> d5 = d1 * d2; | |
decimal<v> d6 = d2 / d1; | |
decimal<v> d7 = d1 - d2; | |
decimal<v> d8 = d1 / d2; | |
printf("decimal<%d>\n", v); | |
printf("\t%.4f + %.4f = %.4f\n", d1.val(), d2.val(), d3.val()); | |
printf("\t%.4f - %.4f = %.4f\n", d2.val(), d1.val(), d4.val()); | |
printf("\t%.4f * %.4f = %.4f\n", d1.val(), d2.val(), d5.val()); | |
printf("\t%.4f / %.4f = %.8f\n", d2.val(), d1.val(), d6.val()); | |
printf("\t%.4f - %.4f = %.4f\n", d1.val(), d2.val(), d7.val()); | |
printf("\t%.4f / %.4f = %.8f\n", d1.val(), d2.val(), d8.val()); | |
d3 = d1 + 25; | |
d4 = d2 - 25; | |
d5 = d1 * 25; | |
d6 = d2 / 2; | |
d7 = d1 - 25; | |
d8 = d1 / 25; | |
printf("\t%.4f + %.d = %.4f\n", d1.val(), 25, d3.val()); | |
printf("\t%.4f - %.d = %.4f\n", d2.val(), 25, d4.val()); | |
printf("\t%.4f * %.d = %.4f\n", d1.val(), 25, d5.val()); | |
printf("\t%.4f / %.d = %.8f\n", d2.val(), 2, d6.val()); | |
printf("\t%.4f - %.d = %.4f\n", d1.val(), 25, d7.val()); | |
printf("\t%.4f / %.d = %.8f\n", d1.val(), 25, d8.val()); | |
d3 += d1; | |
d4 -= d2; | |
d5 *= d1; | |
d6 /= d2; | |
printf("%.4f, %.4f, %.4f, %.4f\n", d3.val(), d4.val(), d5.val(), d6.val()); | |
puts(""); | |
} | |
int main() | |
{ | |
print_decimal<2>(); | |
print_decimal<4>(); | |
print_decimal<6>(); | |
print_decimal<8>(); | |
print_decimal<16>(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment