Compare commits
7 commits
c06444f90c
...
31dcb91a26
Author | SHA1 | Date | |
---|---|---|---|
Bruno BELANYI | 31dcb91a26 | ||
Bruno BELANYI | c730705a13 | ||
Bruno BELANYI | 4b85d22923 | ||
Bruno BELANYI | c9811fce44 | ||
Bruno BELANYI | 2046d1ec4b | ||
Bruno BELANYI | f64c8775f3 | ||
Bruno BELANYI | 7f81f5fa7c |
|
@ -60,7 +60,7 @@
|
||||||
|
|
||||||
devShell = pkgs.mkShell {
|
devShell = pkgs.mkShell {
|
||||||
inherit (self.defaultPackage.${system})
|
inherit (self.defaultPackage.${system})
|
||||||
buildInputs
|
checkInputs
|
||||||
nativeBuildInputs
|
nativeBuildInputs
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -82,11 +82,12 @@
|
||||||
pkg-config
|
pkg-config
|
||||||
];
|
];
|
||||||
|
|
||||||
buildInputs = with pkgs; [
|
checkInputs = with pkgs; [
|
||||||
gtest
|
gtest
|
||||||
];
|
];
|
||||||
|
|
||||||
meta = with pkgs.lib; {
|
meta = with pkgs.lib; {
|
||||||
|
broken = true; # Only breaks under nix
|
||||||
description = "A simple calculator using big numbers";
|
description = "A simple calculator using big numbers";
|
||||||
homepage = "https://gitea.belanyi.fr/ambroisie/abacus";
|
homepage = "https://gitea.belanyi.fr/ambroisie/abacus";
|
||||||
license = licenses.mit;
|
license = licenses.mit;
|
||||||
|
|
|
@ -24,7 +24,7 @@ bool do_less_than(digits_type const& lhs, digits_type const& rhs) {
|
||||||
rhs.rend());
|
rhs.rend());
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_trim_leading_zeros(digits_type& num) {
|
void trim_leading_zeros(digits_type& num) {
|
||||||
auto const it
|
auto const it
|
||||||
= std::find_if(num.rbegin(), num.rend(), [](auto v) { return v != 0; });
|
= std::find_if(num.rbegin(), num.rend(), [](auto v) { return v != 0; });
|
||||||
num.erase(it.base(), num.end());
|
num.erase(it.base(), num.end());
|
||||||
|
@ -82,7 +82,7 @@ digits_type do_substraction(digits_type const& lhs, digits_type const& rhs) {
|
||||||
std::transform(complement.begin(), complement.end(), complement.begin(),
|
std::transform(complement.begin(), complement.end(), complement.begin(),
|
||||||
take_complement);
|
take_complement);
|
||||||
|
|
||||||
do_trim_leading_zeros(complement);
|
trim_leading_zeros(complement);
|
||||||
|
|
||||||
return complement;
|
return complement;
|
||||||
}
|
}
|
||||||
|
@ -150,7 +150,7 @@ digits_type do_halve(digits_type num) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
do_trim_leading_zeros(num);
|
trim_leading_zeros(num);
|
||||||
|
|
||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
|
@ -361,7 +361,7 @@ bool BigNum::less_than(BigNum const& rhs) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void BigNum::canonicalize() {
|
void BigNum::canonicalize() {
|
||||||
do_trim_leading_zeros(digits_);
|
trim_leading_zeros(digits_);
|
||||||
|
|
||||||
if (digits_.size() == 0) {
|
if (digits_.size() == 0) {
|
||||||
sign_ = 0;
|
sign_ = 0;
|
||||||
|
@ -413,8 +413,8 @@ std::pair<BigNum, BigNum> div_mod(BigNum const& lhs, BigNum const& rhs) {
|
||||||
return std::make_pair(BigNum(), BigNum());
|
return std::make_pair(BigNum(), BigNum());
|
||||||
}
|
}
|
||||||
|
|
||||||
BigNum quotient;
|
auto quotient = BigNum(0);
|
||||||
BigNum remainder;
|
auto remainder = BigNum(0);
|
||||||
|
|
||||||
std::tie(quotient.digits_, remainder.digits_)
|
std::tie(quotient.digits_, remainder.digits_)
|
||||||
= do_div_mod(lhs.digits_, rhs.digits_);
|
= do_div_mod(lhs.digits_, rhs.digits_);
|
||||||
|
@ -439,7 +439,7 @@ BigNum pow(BigNum const& lhs, BigNum const& rhs) {
|
||||||
return BigNum();
|
return BigNum();
|
||||||
}
|
}
|
||||||
|
|
||||||
BigNum res;
|
auto res = BigNum(0);
|
||||||
res.digits_ = do_pow(lhs.digits_, rhs.digits_);
|
res.digits_ = do_pow(lhs.digits_, rhs.digits_);
|
||||||
|
|
||||||
res.sign_ = is_odd(rhs.digits_) ? lhs.sign_ : 1;
|
res.sign_ = is_odd(rhs.digits_) ? lhs.sign_ : 1;
|
||||||
|
@ -458,7 +458,7 @@ BigNum sqrt(BigNum const& num) {
|
||||||
"attempt to take the square root of a negative number");
|
"attempt to take the square root of a negative number");
|
||||||
}
|
}
|
||||||
|
|
||||||
BigNum res;
|
auto res = BigNum(0);
|
||||||
|
|
||||||
res.digits_ = do_sqrt(num.digits_);
|
res.digits_ = do_sqrt(num.digits_);
|
||||||
res.sign_ = 1;
|
res.sign_ = 1;
|
||||||
|
@ -468,4 +468,46 @@ BigNum sqrt(BigNum const& num) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BigNum log2(BigNum const& num) {
|
||||||
|
assert(num.is_canonicalized());
|
||||||
|
|
||||||
|
if (num.is_zero()) {
|
||||||
|
throw std::invalid_argument("attempt to take the log2 of zero");
|
||||||
|
} else if (num.is_negative()) {
|
||||||
|
throw std::invalid_argument(
|
||||||
|
"attempt to take the log2 of a negative number");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto tmp = num;
|
||||||
|
auto res = BigNum(0);
|
||||||
|
auto one = BigNum(1);
|
||||||
|
|
||||||
|
while (tmp > one) {
|
||||||
|
tmp.digits_ = do_halve(tmp.digits_);
|
||||||
|
res += one;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(res.is_canonicalized());
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
BigNum log10(BigNum const& num) {
|
||||||
|
assert(num.is_canonicalized());
|
||||||
|
assert(BASE == 10);
|
||||||
|
|
||||||
|
if (num.is_zero()) {
|
||||||
|
throw std::invalid_argument("attempt to take the log10 of zero");
|
||||||
|
} else if (num.is_negative()) {
|
||||||
|
throw std::invalid_argument(
|
||||||
|
"attempt to take the log10 of a negative number");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto res = BigNum(num.digits_.size() - 1);
|
||||||
|
|
||||||
|
assert(res.is_canonicalized());
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace abacus::bignum
|
} // namespace abacus::bignum
|
||||||
|
|
|
@ -91,6 +91,10 @@ public:
|
||||||
|
|
||||||
friend BigNum sqrt(BigNum const& num);
|
friend BigNum sqrt(BigNum const& num);
|
||||||
|
|
||||||
|
friend BigNum log2(BigNum const& num);
|
||||||
|
|
||||||
|
friend BigNum log10(BigNum const& num);
|
||||||
|
|
||||||
friend bool operator==(BigNum const& lhs, BigNum const& rhs) {
|
friend bool operator==(BigNum const& lhs, BigNum const& rhs) {
|
||||||
return lhs.equal(rhs);
|
return lhs.equal(rhs);
|
||||||
}
|
}
|
||||||
|
@ -115,6 +119,10 @@ public:
|
||||||
return !(lhs < rhs);
|
return !(lhs < rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
explicit operator bool() {
|
||||||
|
return !is_zero();
|
||||||
|
}
|
||||||
|
|
||||||
bool is_zero() const;
|
bool is_zero() const;
|
||||||
bool is_positive() const;
|
bool is_positive() const;
|
||||||
bool is_negative() const;
|
bool is_negative() const;
|
||||||
|
|
|
@ -376,3 +376,44 @@ TEST(BigNum, sqrt) {
|
||||||
EXPECT_EQ(sqrt(ninety_nine), nine);
|
EXPECT_EQ(sqrt(ninety_nine), nine);
|
||||||
EXPECT_EQ(sqrt(hundred), ten);
|
EXPECT_EQ(sqrt(hundred), ten);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(BigNum, log2) {
|
||||||
|
auto const zero = BigNum(0);
|
||||||
|
auto const one = BigNum(1);
|
||||||
|
auto const two = BigNum(2);
|
||||||
|
auto const three = BigNum(3);
|
||||||
|
auto const four = BigNum(4);
|
||||||
|
auto const five = BigNum(5);
|
||||||
|
auto const seven = BigNum(7);
|
||||||
|
auto const eight = BigNum(8);
|
||||||
|
auto const nine = BigNum(9);
|
||||||
|
|
||||||
|
EXPECT_EQ(log2(one), zero);
|
||||||
|
EXPECT_EQ(log2(two), one);
|
||||||
|
EXPECT_EQ(log2(three), one);
|
||||||
|
EXPECT_EQ(log2(four), two);
|
||||||
|
EXPECT_EQ(log2(five), two);
|
||||||
|
EXPECT_EQ(log2(seven), two);
|
||||||
|
EXPECT_EQ(log2(eight), three);
|
||||||
|
EXPECT_EQ(log2(nine), three);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(BigNum, log10) {
|
||||||
|
auto const zero = BigNum(0);
|
||||||
|
auto const one = BigNum(1);
|
||||||
|
auto const two = BigNum(2);
|
||||||
|
auto const nine = BigNum(9);
|
||||||
|
auto const ten = BigNum(10);
|
||||||
|
auto const eleven = BigNum(11);
|
||||||
|
auto const ninety_nine = BigNum(99);
|
||||||
|
auto const hundred = BigNum(100);
|
||||||
|
auto const hundred_one = BigNum(101);
|
||||||
|
|
||||||
|
EXPECT_EQ(log10(one), zero);
|
||||||
|
EXPECT_EQ(log10(nine), zero);
|
||||||
|
EXPECT_EQ(log10(ten), one);
|
||||||
|
EXPECT_EQ(log10(eleven), one);
|
||||||
|
EXPECT_EQ(log10(ninety_nine), one);
|
||||||
|
EXPECT_EQ(log10(hundred), two);
|
||||||
|
EXPECT_EQ(log10(hundred_one), two);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue