diff --git a/README.md b/README.md index 000eb59e2..409ef7a61 100644 --- a/README.md +++ b/README.md @@ -105,9 +105,9 @@ sudo rm -rf /usr/local/share/meevax | Target Name | Description |:-------------------|:-- -| `all` (default) | Build shared-library `libmeevax.0.4.197.so` and executable `meevax`. +| `all` (default) | Build shared-library `libmeevax.0.4.208.so` and executable `meevax`. | `test` | Test executable `meevax`. -| `package` | Generate debian package `meevax_0.4.197_amd64.deb`. +| `package` | Generate debian package `meevax_0.4.208_amd64.deb`. | `install` | Copy files into `/usr/local` __(1)__. | `install.deb` | `all` + `package` + `sudo apt install .deb` | `safe-install.deb` | `all` + `test` + `package` + `sudo apt install .deb` @@ -122,7 +122,7 @@ __(1)__ Meevax installed by `make install` cannot be uninstalled by the system's ## Usage ``` -Meevax Lisp System, version 0.4.197 +Meevax Lisp System, version 0.4.208 Usage: meevax [OPTION...] [FILE...] diff --git a/VERSION b/VERSION index 3b43aa39c..cab5b51e7 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.4.197 +0.4.208 diff --git a/basis/r4rs.ss b/basis/r4rs.ss index 71e161739..f9d21a52f 100644 --- a/basis/r4rs.ss +++ b/basis/r4rs.ss @@ -1,6 +1,6 @@ (define-library (scheme r4rs) (import (meevax inexact) - (only (meevax number) exact-integer? expt exact inexact ratio?) + (only (meevax number) exact-integer? expt exact inexact ratio? ratio-numerator ratio-denominator) (only (meevax port) get-ready? standard-input-port standard-output-port) (only (meevax string) string-copy) (only (meevax syntax) define-syntax) @@ -71,12 +71,13 @@ ,body))))))) (define (numerator x) - (cond ((ratio? x) (car x)) + (cond ((ratio? x) (ratio-numerator x)) ((exact? x) x) (else (inexact (numerator (exact x)))))) (define (denominator x) - (cond ((exact? x) (if (ratio? x) (cdr x) 1)) + (cond ((ratio? x) (ratio-denominator x)) + ((exact? x) 1) ((integer? x) 1.0) (else (inexact (denominator (exact x)))))) diff --git a/include/meevax/kernel/exact_integer.hpp b/include/meevax/kernel/exact_integer.hpp index 37c6a7af3..daba883ea 100644 --- a/include/meevax/kernel/exact_integer.hpp +++ b/include/meevax/kernel/exact_integer.hpp @@ -29,13 +29,15 @@ inline namespace kernel { mpz_t value; - explicit exact_integer() noexcept; - - explicit exact_integer(mpz_t) noexcept; + exact_integer() noexcept; exact_integer(exact_integer const&) noexcept; - explicit exact_integer(exact_integer &&) noexcept; + exact_integer(exact_integer &&) noexcept; + + ~exact_integer(); + + explicit exact_integer(mpz_t const) noexcept; explicit exact_integer(int); @@ -47,18 +49,12 @@ inline namespace kernel explicit exact_integer(external_representation const&, int = 0); - ~exact_integer(); - auto operator=(exact_integer const&) -> exact_integer &; auto operator=(exact_integer &&) noexcept -> exact_integer &; auto operator=(external_representation const&) -> exact_integer &; - auto swap(exact_integer &) noexcept -> void; - - explicit operator bool() const; - operator int() const; operator signed long() const; @@ -68,6 +64,8 @@ inline namespace kernel explicit operator float() const; explicit operator double() const; + + explicit operator bool() const; }; auto operator ==(exact_integer const&, int const) -> bool; diff --git a/include/meevax/kernel/number.hpp b/include/meevax/kernel/number.hpp index 4f60e492c..0363d66ff 100644 --- a/include/meevax/kernel/number.hpp +++ b/include/meevax/kernel/number.hpp @@ -195,7 +195,14 @@ inline namespace kernel } else if constexpr (std::is_same_v, ratio>) { - return z.simple(); + if (z.denominator() == 1) + { + return make(z.numerator()); + } + else + { + return make(std::forward(z)); + } } else { @@ -256,21 +263,18 @@ inline namespace kernel struct exact { template - auto operator ()(T const& x) const -> decltype(auto) - { - return ratio(x).simple(); - } - - auto operator ()(exact_integer const& x) const -> auto const& - { - return x; - } - - auto operator ()(ratio const& x) const -> auto const& + auto operator ()(T&& x) const -> decltype(auto) { - return x; + if constexpr (std::is_floating_point_v>) + { + return ratio(std::forward(x)); + } + else + { + return std::forward(x); + } } - }; + } inline constexpr exact_cast; struct inexact { @@ -376,7 +380,7 @@ inline namespace kernel } else if constexpr (std::is_same_v, ratio>) { - return x.denominator().template as() == 1; + return x.denominator() == 1; } else { diff --git a/include/meevax/kernel/ratio.hpp b/include/meevax/kernel/ratio.hpp index c90daacf9..1b6a04d5f 100644 --- a/include/meevax/kernel/ratio.hpp +++ b/include/meevax/kernel/ratio.hpp @@ -17,33 +17,36 @@ #ifndef INCLUDED_MEEVAX_KERNEL_RATIO_HPP #define INCLUDED_MEEVAX_KERNEL_RATIO_HPP +#include #include namespace meevax { inline namespace kernel { - struct ratio : public virtual pair + struct ratio { - using pair::pair; + mpq_t value; - explicit ratio(double); + ratio(); + + ratio(ratio const&); - explicit ratio(external_representation const&, int = 0); + ratio(ratio &&); - auto denominator() const -> const_reference; + ~ratio(); - auto denominator() -> reference; + explicit ratio(exact_integer const&); - auto invert() const -> ratio; + explicit ratio(exact_integer const&, exact_integer const&); - auto numerator() const -> const_reference; + explicit ratio(double); - auto numerator() -> reference; + explicit ratio(external_representation const&, int = 10); - auto reduce() const -> ratio; + auto denominator() const -> exact_integer; - auto simple() const -> value_type; + auto numerator() const -> exact_integer; explicit operator double() const; }; diff --git a/include/meevax/kernel/reader.hpp b/include/meevax/kernel/reader.hpp index 20056d882..d9a564e71 100644 --- a/include/meevax/kernel/reader.hpp +++ b/include/meevax/kernel/reader.hpp @@ -244,7 +244,7 @@ inline namespace kernel { try { - return ratio(token, radix).simple(); + return make(ratio(token, radix)); } catch (...) { diff --git a/src/kernel/exact_integer.cpp b/src/kernel/exact_integer.cpp index 4c3f34b83..38e20a53d 100644 --- a/src/kernel/exact_integer.cpp +++ b/src/kernel/exact_integer.cpp @@ -31,20 +31,25 @@ inline namespace kernel mpz_init(value); } - exact_integer::exact_integer(mpz_t given) noexcept + exact_integer::exact_integer(exact_integer const& other) noexcept { - mpz_init_set(value, given); + mpz_init_set(value, other.value); } - exact_integer::exact_integer(exact_integer const& given) noexcept + exact_integer::exact_integer(exact_integer && other) noexcept { - mpz_init_set(value, given.value); + mpz_init(value); + mpz_swap(value, other.value); } - exact_integer::exact_integer(exact_integer && rhs) noexcept + exact_integer::~exact_integer() { - *value = *rhs.value; - mpz_init(rhs.value); + mpz_clear(value); + } + + exact_integer::exact_integer(mpz_t const z) noexcept + { + mpz_init_set(value, z); } exact_integer::exact_integer(int rhs) @@ -75,20 +80,15 @@ inline namespace kernel } } - exact_integer::~exact_integer() - { - mpz_clear(value); - } - auto exact_integer::operator=(exact_integer const& rhs) -> exact_integer & { mpz_set(value, rhs.value); return *this; } - auto exact_integer::operator=(exact_integer && rhs) noexcept -> exact_integer & + auto exact_integer::operator=(exact_integer && other) noexcept -> exact_integer & { - swap(rhs); + mpz_swap(value, other.value); return *this; } @@ -104,11 +104,6 @@ inline namespace kernel } } - auto exact_integer::swap(exact_integer & rhs) noexcept -> void - { - std::swap(*value, *rhs.value); - } - exact_integer::operator bool() const { return (*value)._mp_size; diff --git a/src/kernel/library.cpp b/src/kernel/library.cpp index ffc2b1213..e4bb7750d 100644 --- a/src/kernel/library.cpp +++ b/src/kernel/library.cpp @@ -569,6 +569,16 @@ inline namespace kernel #undef DEFINE + library.define("ratio-numerator", [](let const& xs) + { + return make(car(xs).as().numerator()); + }); + + library.define("ratio-denominator", [](let const& xs) + { + return make(car(xs).as().denominator()); + }); + library.define("floor", [](let const& xs) { return apply(car(xs)); @@ -648,6 +658,8 @@ inline namespace kernel library.export_("-"); library.export_("/"); library.export_("%"); + library.export_("ratio-numerator"); + library.export_("ratio-denominator"); library.export_("floor"); library.export_("ceiling"); library.export_("truncate"); diff --git a/src/kernel/number.cpp b/src/kernel/number.cpp index 2fc627752..06cdd5220 100644 --- a/src/kernel/number.cpp +++ b/src/kernel/number.cpp @@ -24,26 +24,26 @@ inline namespace kernel auto operator + (exact_integer const& a, exact_integer const& b) -> exact_integer { exact_integer n; mpz_add(n.value, a.value, b.value); return n; } auto operator - (exact_integer const& a, exact_integer const& b) -> exact_integer { exact_integer n; mpz_sub(n.value, a.value, b.value); return n; } auto operator * (exact_integer const& a, exact_integer const& b) -> exact_integer { exact_integer n; mpz_mul(n.value, a.value, b.value); return n; } - auto operator / (exact_integer const& a, exact_integer const& b) -> ratio { return ratio(make(a), make(b)); } + auto operator / (exact_integer const& a, exact_integer const& b) -> ratio { return ratio(a, b); } auto operator % (exact_integer const& a, exact_integer const& b) -> exact_integer { exact_integer n; mpz_tdiv_r(n.value, a.value, b.value); return n; } + auto operator ==(exact_integer const& a, exact_integer const& b) -> bool { return mpz_cmp(a.value, b.value) == 0; } auto operator !=(exact_integer const& a, exact_integer const& b) -> bool { return mpz_cmp(a.value, b.value) != 0; } auto operator < (exact_integer const& a, exact_integer const& b) -> bool { return mpz_cmp(a.value, b.value) < 0; } auto operator <=(exact_integer const& a, exact_integer const& b) -> bool { return mpz_cmp(a.value, b.value) <= 0; } - auto operator ==(exact_integer const& a, exact_integer const& b) -> bool { return mpz_cmp(a.value, b.value) == 0; } auto operator > (exact_integer const& a, exact_integer const& b) -> bool { return mpz_cmp(a.value, b.value) > 0; } auto operator >=(exact_integer const& a, exact_integer const& b) -> bool { return mpz_cmp(a.value, b.value) >= 0; } - auto operator * (exact_integer const& a, ratio const& b) -> ratio { return ratio(make(a * b.numerator().as()), cdr(b)); } - auto operator + (exact_integer const& a, ratio const& b) -> ratio { return ratio(make(a * b.denominator().as() + b.numerator().as()), cdr(b)); } - auto operator - (exact_integer const& a, ratio const& b) -> ratio { return ratio(make(a * b.denominator().as() - b.numerator().as()), cdr(b)); } - auto operator / (exact_integer const& a, ratio const& b) -> ratio { return a * b.invert(); } + auto operator + (exact_integer const& a, ratio const& b) -> ratio { ratio q; mpq_add(q.value, ratio(a).value, b.value); return q; } + auto operator - (exact_integer const& a, ratio const& b) -> ratio { ratio q; mpq_sub(q.value, ratio(a).value, b.value); return q; } + auto operator * (exact_integer const& a, ratio const& b) -> ratio { ratio q; mpq_mul(q.value, ratio(a).value, b.value); return q; } + auto operator / (exact_integer const& a, ratio const& b) -> ratio { ratio q; mpq_div(q.value, ratio(a).value, b.value); return q; } auto operator % (exact_integer const& , ratio const& ) -> ratio { throw error(make("unsupported operation"), unit); } - auto operator !=(exact_integer const& a, ratio const& b) -> bool { auto const x = b.reduce(); return std::invoke(is_integer(), x) and a != x.numerator().as(); } - auto operator < (exact_integer const& a, ratio const& b) -> bool { auto const x = b.reduce(); return std::invoke(is_integer(), x) and a < x.numerator().as(); } - auto operator <=(exact_integer const& a, ratio const& b) -> bool { auto const x = b.reduce(); return std::invoke(is_integer(), x) and a <= x.numerator().as(); } - auto operator ==(exact_integer const& a, ratio const& b) -> bool { auto const x = b.reduce(); return std::invoke(is_integer(), x) and a == x.numerator().as(); } - auto operator > (exact_integer const& a, ratio const& b) -> bool { auto const x = b.reduce(); return std::invoke(is_integer(), x) and a > x.numerator().as(); } - auto operator >=(exact_integer const& a, ratio const& b) -> bool { auto const x = b.reduce(); return std::invoke(is_integer(), x) and a >= x.numerator().as(); } + auto operator ==(exact_integer const& a, ratio const& b) -> bool { return mpq_cmp_z(b.value, a.value) == 0; } + auto operator !=(exact_integer const& a, ratio const& b) -> bool { return mpq_cmp_z(b.value, a.value) != 0; } + auto operator < (exact_integer const& a, ratio const& b) -> bool { return mpq_cmp_z(b.value, a.value) > 0; } + auto operator <=(exact_integer const& a, ratio const& b) -> bool { return mpq_cmp_z(b.value, a.value) >= 0; } + auto operator > (exact_integer const& a, ratio const& b) -> bool { return mpq_cmp_z(b.value, a.value) < 0; } + auto operator >=(exact_integer const& a, ratio const& b) -> bool { return mpq_cmp_z(b.value, a.value) <= 0; } auto operator + (exact_integer const& a, float b) -> float { return inexact_cast(a) + b; } auto operator - (exact_integer const& a, float b) -> float { return inexact_cast(a) - b; } @@ -69,29 +69,29 @@ inline namespace kernel auto operator > (exact_integer const& a, double b) -> bool { return mpz_cmp_d(a.value, b) > 0; } auto operator >=(exact_integer const& a, double b) -> bool { return mpz_cmp_d(a.value, b) >= 0; } - auto operator * (ratio const& a, exact_integer const& b) -> ratio { return ratio(make(a.numerator().as() * b), cdr(a)); } - auto operator + (ratio const& a, exact_integer const& b) -> ratio { return ratio(make(a.numerator().as() + a.denominator().as() * b), cdr(a)); } - auto operator - (ratio const& a, exact_integer const& b) -> ratio { return ratio(make(a.numerator().as() - a.denominator().as() * b), cdr(a)); } - auto operator / (ratio const& a, exact_integer const& b) -> ratio { return ratio(car(a), make(a.denominator().as() * b)); } + auto operator + (ratio const& a, exact_integer const& b) -> ratio { ratio q; mpq_add(q.value, a.value, ratio(b).value); return q; } + auto operator - (ratio const& a, exact_integer const& b) -> ratio { ratio q; mpq_sub(q.value, a.value, ratio(b).value); return q; } + auto operator * (ratio const& a, exact_integer const& b) -> ratio { ratio q; mpq_mul(q.value, a.value, ratio(b).value); return q; } + auto operator / (ratio const& a, exact_integer const& b) -> ratio { ratio q; mpq_div(q.value, a.value, ratio(b).value); return q; } auto operator % (ratio const& , exact_integer const& ) -> ratio { throw error(make("unsupported operation"), unit); } - auto operator !=(ratio const& a, exact_integer const& b) -> bool { auto const x = a.reduce(); return std::invoke(is_integer(), x) and x.numerator().as() != b; } - auto operator < (ratio const& a, exact_integer const& b) -> bool { auto const x = a.reduce(); return std::invoke(is_integer(), x) and x.numerator().as() < b; } - auto operator <=(ratio const& a, exact_integer const& b) -> bool { auto const x = a.reduce(); return std::invoke(is_integer(), x) and x.numerator().as() <= b; } - auto operator ==(ratio const& a, exact_integer const& b) -> bool { auto const x = a.reduce(); return std::invoke(is_integer(), x) and x.numerator().as() == b; } - auto operator > (ratio const& a, exact_integer const& b) -> bool { auto const x = a.reduce(); return std::invoke(is_integer(), x) and x.numerator().as() > b; } - auto operator >=(ratio const& a, exact_integer const& b) -> bool { auto const x = a.reduce(); return std::invoke(is_integer(), x) and x.numerator().as() >= b; } - - auto operator + (ratio const& a, ratio const& b) -> ratio { return ratio(make(a.numerator().as() * b.denominator().as() + b.numerator().as() * a.denominator().as()), make(a.denominator().as() * b.denominator().as())); } - auto operator - (ratio const& a, ratio const& b) -> ratio { return ratio(make(a.numerator().as() * b.denominator().as() - b.numerator().as() * a.denominator().as()), make(a.denominator().as() * b.denominator().as())); } - auto operator * (ratio const& a, ratio const& b) -> ratio { return ratio(make(a.numerator().as() * b.numerator().as()), make(a.denominator().as() * b.denominator().as())); } - auto operator / (ratio const& a, ratio const& b) -> ratio { return a * b.invert(); } + auto operator ==(ratio const& a, exact_integer const& b) -> bool { return mpq_cmp_z(a.value, b.value) == 0; } + auto operator !=(ratio const& a, exact_integer const& b) -> bool { return mpq_cmp_z(a.value, b.value) != 0; } + auto operator < (ratio const& a, exact_integer const& b) -> bool { return mpq_cmp_z(a.value, b.value) < 0; } + auto operator <=(ratio const& a, exact_integer const& b) -> bool { return mpq_cmp_z(a.value, b.value) <= 0; } + auto operator > (ratio const& a, exact_integer const& b) -> bool { return mpq_cmp_z(a.value, b.value) > 0; } + auto operator >=(ratio const& a, exact_integer const& b) -> bool { return mpq_cmp_z(a.value, b.value) >= 0; } + + auto operator + (ratio const& a, ratio const& b) -> ratio { ratio q; mpq_add(q.value, a.value, b.value); return q; } + auto operator - (ratio const& a, ratio const& b) -> ratio { ratio q; mpq_sub(q.value, a.value, b.value); return q; } + auto operator * (ratio const& a, ratio const& b) -> ratio { ratio q; mpq_mul(q.value, a.value, b.value); return q; } + auto operator / (ratio const& a, ratio const& b) -> ratio { ratio q; mpq_div(q.value, a.value, b.value); return q; } auto operator % (ratio const& , ratio const& ) -> ratio { throw error(make("unsupported operation"), unit); } - auto operator ==(ratio const& a, ratio const& b) -> bool { return (a.numerator().as() * b.denominator().as()) == (b.numerator().as() * a.denominator().as()); } - auto operator !=(ratio const& a, ratio const& b) -> bool { return (a.numerator().as() * b.denominator().as()) != (b.numerator().as() * a.denominator().as()); } - auto operator < (ratio const& a, ratio const& b) -> bool { return (a.numerator().as() * b.denominator().as()) < (b.numerator().as() * a.denominator().as()); } - auto operator <=(ratio const& a, ratio const& b) -> bool { return (a.numerator().as() * b.denominator().as()) <= (b.numerator().as() * a.denominator().as()); } - auto operator > (ratio const& a, ratio const& b) -> bool { return (a.numerator().as() * b.denominator().as()) > (b.numerator().as() * a.denominator().as()); } - auto operator >=(ratio const& a, ratio const& b) -> bool { return (a.numerator().as() * b.denominator().as()) >= (b.numerator().as() * a.denominator().as()); } + auto operator ==(ratio const& a, ratio const& b) -> bool { return mpq_cmp(a.value, b.value) == 0; } + auto operator !=(ratio const& a, ratio const& b) -> bool { return mpq_cmp(a.value, b.value) != 0; } + auto operator < (ratio const& a, ratio const& b) -> bool { return mpq_cmp(a.value, b.value) < 0; } + auto operator <=(ratio const& a, ratio const& b) -> bool { return mpq_cmp(a.value, b.value) <= 0; } + auto operator > (ratio const& a, ratio const& b) -> bool { return mpq_cmp(a.value, b.value) > 0; } + auto operator >=(ratio const& a, ratio const& b) -> bool { return mpq_cmp(a.value, b.value) >= 0; } auto operator + (ratio const& a, float b) -> float { return inexact_cast(a) + b; } auto operator - (ratio const& a, float b) -> float { return inexact_cast(a) - b; } @@ -148,10 +148,10 @@ inline namespace kernel auto operator % (double a, exact_integer const& b) -> double { return std::remainder(a, inexact_cast(b)); } auto operator ==(double a, exact_integer const& b) -> bool { return mpz_cmp_d(b.value, a) == 0; } auto operator !=(double a, exact_integer const& b) -> bool { return mpz_cmp_d(b.value, a) != 0; } - auto operator < (double a, exact_integer const& b) -> bool { return a < inexact_cast(b); } - auto operator <=(double a, exact_integer const& b) -> bool { return a <= inexact_cast(b); } - auto operator > (double a, exact_integer const& b) -> bool { return a > inexact_cast(b); } - auto operator >=(double a, exact_integer const& b) -> bool { return a >= inexact_cast(b); } + auto operator < (double a, exact_integer const& b) -> bool { return mpz_cmp_d(b.value, a) > 0; } + auto operator <=(double a, exact_integer const& b) -> bool { return mpz_cmp_d(b.value, a) >= 0; } + auto operator > (double a, exact_integer const& b) -> bool { return mpz_cmp_d(b.value, a) < 0; } + auto operator >=(double a, exact_integer const& b) -> bool { return mpz_cmp_d(b.value, a) <= 0; } auto operator + (double a, ratio const& b) -> double { return a + inexact_cast(b); } auto operator - (double a, ratio const& b) -> double { return a - inexact_cast(b); } diff --git a/src/kernel/ratio.cpp b/src/kernel/ratio.cpp index 2a968ca65..fc5880337 100644 --- a/src/kernel/ratio.cpp +++ b/src/kernel/ratio.cpp @@ -22,111 +22,90 @@ namespace meevax { inline namespace kernel { - ratio::ratio(double x) + ratio::ratio() { - mpq_t value; mpq_init(value); - mpq_set_d(value, x); - - numerator() = make(mpq_numref(value)); - - denominator() = make(mpq_denref(value)); - - mpq_clear(value); } - ratio::ratio(external_representation const& token, int radix) + ratio::ratio(ratio const& other) { - std::regex static const pattern { "([+-]?[0-9a-f]+)/([0-9a-f]+)" }; - - if (std::smatch result; std::regex_match(token, result, pattern)) - { - auto n = exact_integer(result.str(1), radix); - - numerator() = make(n); - - auto d = exact_integer(result.str(2), radix); - - denominator() = make(d); - } - else - { - throw error(); - } - } - - auto ratio::denominator() const -> const_reference - { - return second; + mpq_init(value); + mpq_set(value, other.value); + mpq_canonicalize(value); } - auto ratio::denominator() -> reference + ratio::ratio(ratio && other) { - return second; + mpq_init(value); + mpq_swap(value, other.value); + mpq_canonicalize(value); } - auto ratio::invert() const -> ratio + ratio::ratio(exact_integer const& z) { - return ratio(denominator(), numerator()); + mpq_init(value); + mpq_set_z(value, z.value); } - auto ratio::numerator() const -> const_reference + ratio::ratio(exact_integer const& n, exact_integer const& d) { - return first; + mpq_init(value); + mpq_set_num(value, n.value); + mpq_set_den(value, d.value); + mpq_canonicalize(value); } - auto ratio::numerator() -> reference + ratio::ratio(double x) { - return first; + mpq_init(value); + mpq_set_d(value, x); } - auto ratio::reduce() const -> ratio + ratio::ratio(external_representation const& token, int radix) { - auto gcd = [](exact_integer const& a, exact_integer const& b) - { - exact_integer n; - mpz_gcd(n.value, a.value, b.value); - return n; - }; - - auto div = [](exact_integer const& a, exact_integer const& b) - { - exact_integer n; - mpz_div(n.value, a.value, b.value); - return n; - }; + // std::regex static const pattern { "([+-]?[0-9a-f]+)/([0-9a-f]+)" }; - if (auto x = gcd(numerator().as(), denominator().as()); x != 1) + if (mpq_init(value); mpq_set_str(value, token.c_str(), radix)) { - return ratio(make(div(numerator().as(), x)), - make(div(denominator().as(), x))); + mpq_clear(value); + throw error(); } else { - return *this; + mpq_canonicalize(value); } } - auto ratio::simple() const -> value_type + ratio::~ratio() { - if (auto x = reduce(); is_integer()(x)) - { - return car(x); - } - else - { - return make(x); - } + mpq_clear(value); + } + + auto ratio::denominator() const -> exact_integer + { + return exact_integer(mpq_denref(value)); + } + + auto ratio::numerator() const -> exact_integer + { + return exact_integer(mpq_numref(value)); } ratio::operator double() const { - return static_cast(numerator().as()) / static_cast(denominator().as()); + return mpq_get_d(value); } auto operator <<(std::ostream & os, ratio const& datum) -> std::ostream & { - return os << datum.numerator() << cyan("/") << datum.denominator(); + auto free = [](char * data) + { + void (*free)(void *, std::size_t); + mp_get_memory_functions(nullptr, nullptr, &free); + std::invoke(free, static_cast(data), std::strlen(data) + 1); + }; + + return os << cyan(std::unique_ptr(mpq_get_str(nullptr, 10, datum.value), free).get()); } } // namespace kernel } // namespace meevax diff --git a/test/numerical-operations.ss b/test/numerical-operations.ss index ef0855fdc..4e5ae4dd9 100644 --- a/test/numerical-operations.ss +++ b/test/numerical-operations.ss @@ -24,7 +24,7 @@ (let ((x (+ 1 1/2))) - (check x => 3/2) + (check x (=> =) 3/2) (check (number? x) => #t) (check (complex? x) => #t) @@ -38,7 +38,7 @@ (let ((x (* 2 1/2))) - (check x => 1) + (check x (=> =) 1) (check (number? x) => #t) (check (complex? x) => #t) @@ -52,7 +52,7 @@ (let ((x (+ 1/3 1/3 1/3))) - (check x => 1) + (check x (=> =) 1) (check (number? x) => #t) (check (complex? x) => #t) @@ -64,17 +64,17 @@ (check (inexact? x) => #f) ) -(check (+ 1 1.0) => 2.0) -(check (+ 1.0 1 ) => 2.0) +(check (+ 1 1.0) (=> =) 2.0) +(check (+ 1.0 1 ) (=> =) 2.0) -(check (+ 1 1/2) => 3/2) -(check (+ 1.0 1/2) => 1.5) +(check (+ 1 1/2) (=> =) 3/2) +(check (+ 1.0 1/2) (=> =) 1.5) -(check (+ 1/2 1 ) => 3/2) -(check (+ 1/2 1.0) => 1.5) +(check (+ 1/2 1 ) (=> =) 3/2) +(check (+ 1/2 1.0) (=> =) 1.5) -(check (* 2 1/2) => 1 ) -(check (* 2.0 1/2) => 1.0) +(check (* 2 1/2) (=> =) 1 ) +(check (* 2.0 1/2) (=> =) 1.0) (check (modulo 13 4) => 1) (check (modulo -13 4) => 3) diff --git a/test/sicp-1.ss b/test/sicp-1.ss index 65dc0b89d..c7bb91687 100644 --- a/test/sicp-1.ss +++ b/test/sicp-1.ss @@ -16,7 +16,7 @@ (check (* 5 99) => 495) -(check (/ 10 5) => 2) +(check (/ 10 5) (=> =) 2) (check (+ 2.7 10) => 12.7) @@ -114,7 +114,7 @@ (check (- 9 1) => 8) -(check (/ 6 2) => 3) +(check (/ 6 2) (=> =) 3) (check (+ (* 2 4) (- 4 6)) => 6)