diff --git a/README.md b/README.md index 276360d10..febdf0941 100644 --- a/README.md +++ b/README.md @@ -97,9 +97,9 @@ Then, select one of the following targets and `make` it according to your purpos | Target | Description |-------------|------------- -| `all` | Build shared-library `libmeevax.0.5.276.so` and executable `meevax`. +| `all` | Build shared-library `libmeevax.0.5.292.so` and executable `meevax`. | `install` | Copy files into `/usr/local` directly. -| `package` | Generate debian package `meevax_0.5.276_amd64.deb` (only Ubuntu). The generated package can be installed by `sudo apt install build/meevax_0.5.276_amd64.deb`. +| `package` | Generate debian package `meevax_0.5.292_amd64.deb` (only Ubuntu). The generated package can be installed by `sudo apt install build/meevax_0.5.292_amd64.deb`. | `test` | Test executable `meevax`. This target requires Valgrind to be installed. | `uninstall` | Remove files copied to `/usr/local` directly by target `install`. diff --git a/VERSION b/VERSION index e132b397f..d9d175dac 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.5.276 +0.5.292 diff --git a/basis/srfi-144.ss b/basis/srfi-144.ss new file mode 100644 index 000000000..283145981 --- /dev/null +++ b/basis/srfi-144.ss @@ -0,0 +1,307 @@ +(define-library (srfi 144) + (import (only (meevax binary64) + FP_FAST_FMA + binary64-abs + binary64-denormalized? + binary64-epsilon + binary64-expm1 + binary64-exponent + binary64-fractional-part + binary64-fused-multiply-add + binary64-greatest + binary64-integer-log-binary + binary64-integral-part + binary64-least + binary64-log-binary + binary64-max + binary64-min + binary64-normalized-fraction + binary64-normalized? + binary64-sign-bit + binary64? + ) + (only (meevax inexact) + copy-sign + e + euler + gamma + load-exponent + next-after + phi + pi + ) + (only (scheme base) + * + + + - + / + < + <= + = + > + >= + and + ceiling + define + denominator + even? + expt + floor + if + inexact + integer? + negative? + numerator + odd? + or + positive? + round + truncate + values + zero? + ) + (only (scheme inexact) + cos + exp + finite? + infinite? + log + nan? + sin + sqrt + ) + ) + + (export fl-e fl-1/e fl-e-2 fl-e-pi/4 fl-log2-e fl-log10-e fl-log-2 fl-1/log-2 + fl-log-3 fl-log-pi fl-log-10 fl-1/log-10 fl-pi fl-1/pi fl-2pi fl-pi/2 + fl-pi/4 fl-pi-squared fl-degree fl-2/pi fl-2/sqrt-pi fl-sqrt-2 + fl-sqrt-3 fl-sqrt-5 fl-sqrt-10 fl-1/sqrt-2 fl-cbrt-2 fl-cbrt-3 + fl-4thrt-2 fl-phi fl-log-phi fl-1/log-phi fl-euler fl-e-euler + fl-sin-1 fl-cos-1 fl-gamma-1/2 fl-gamma-1/3 fl-gamma-2/3 + + fl-greatest fl-least fl-epsilon fl-fast-fl+* fl-integer-exponent-zero + fl-integer-exponent-nan + + flonum fladjacent flcopysign make-flonum + + flinteger-fraction flexponent flinteger-exponent + flnormalized-fraction-exponent flsign-bit + + flonum? fl=? fl? fl<=? fl>=? flunordered? flinteger? flzero? + flpositive? flnegative? flodd? fleven? flfinite? flinfinite? flnan? + flnormalized? fldenormalized? + + flmax flmin fl+ fl* fl+* fl- fl/ flabs flabsdiff flposdiff flsgn + flnumerator fldenominator flfloor flceiling flround fltruncate + + flexp flexp2 flexp-1 + ; flsquare flsqrt flcbrt flhypot flexpt fllog + ; fllog1+ fllog2 fllog10 make-fllog-base + ; + ; flsin flcos fltan flasin flacos flatan + ; flsinh flcosh fltanh flasinh flacosh flatanh + ; + ; flquotient flremainder flremquo + ; + ; flgamma flloggamma flfirst-bessel flsecond-bessel + ; flerf flerfc + ) + + (begin (define fl-e e) + + (define fl-1/e (/ 1 e)) + + (define fl-e-2 7.38905609893065) ; (define fl-e-2 (expt e 2)) yields 1 ULP error + + (define fl-e-pi/4 (expt e (/ pi 4))) + + (define fl-log2-e (log e 2)) + + (define fl-log10-e 0.4342944819032518) ; (define fl-log10-e (log e 10)) yields 1 ULP error + + (define fl-log-2 (log 2)) + + (define fl-1/log-2 (/ 1 (log 2))) + + (define fl-log-3 (log 3)) + + (define fl-log-pi (log pi)) + + (define fl-log-10 (log 10)) + + (define fl-1/log-10 0.4342944819032518) ; (define fl-1/log-10 (/ 1 (log 10))) yields 1 ULP error + + (define fl-pi pi) + + (define fl-1/pi (/ 1 pi)) + + (define fl-2pi (* 2 pi)) + + (define fl-pi/2 (/ pi 2)) + + (define fl-pi/4 (/ pi 4)) + + (define fl-pi-squared (expt pi 2)) + + (define fl-degree (/ pi 180)) + + (define fl-2/pi (/ 2 pi)) + + (define fl-2/sqrt-pi (/ 2 (sqrt pi))) + + (define fl-sqrt-2 (sqrt 2)) + + (define fl-sqrt-3 (sqrt 3)) + + (define fl-sqrt-5 (sqrt 5)) + + (define fl-sqrt-10 (sqrt 10)) + + (define fl-1/sqrt-2 (/ 1 (sqrt 2))) + + (define fl-cbrt-2 (expt 2 (/ 1 3))) + + (define fl-cbrt-3 (expt 3 (/ 1 3))) + + (define fl-4thrt-2 (expt 2 (/ 1 4))) + + (define fl-phi phi) + + (define fl-log-phi (log phi)) + + (define fl-1/log-phi 2.07808692123502753) ; (define fl-1/log-phi (/ 1 fl-log-phi)) yields 1 ULP error + + (define fl-euler euler) + + (define fl-e-euler (expt e euler)) + + (define fl-sin-1 (sin 1)) + + (define fl-cos-1 (cos 1)) + + (define fl-gamma-1/2 (gamma (/ 1 2))) + + (define fl-gamma-1/3 2.67893853470774763) ; (define fl-gamma-1/3 (gamma (/ 1 3))) yields 1 ULP error + + (define fl-gamma-2/3 (gamma (/ 2 3))) + + (define fl-greatest binary64-greatest) + + (define fl-least binary64-least) + + (define fl-epsilon binary64-epsilon) + + (define fl-fast-fl+* FP_FAST_FMA) + + (define fl-integer-exponent-zero (binary64-integer-log-binary 0.0)) + + (define fl-integer-exponent-nan (binary64-integer-log-binary +nan.0)) + + (define flonum inexact) + + (define fladjacent next-after) + + (define flcopysign copy-sign) + + (define make-flonum load-exponent) + + (define (flinteger-fraction x) + (values (binary64-integral-part x) + (binary64-fractional-part x))) + + (define flexponent binary64-log-binary) + + (define flinteger-exponent binary64-integer-log-binary) + + (define (flnormalized-fraction-exponent x) + (values (binary64-normalized-fraction x) + (binary64-exponent x))) + + (define (flsign-bit x) + (if (binary64-sign-bit x) 1 0)) + + (define flonum? binary64?) + + (define fl=? =) + + (define fl? >) + + (define fl<=? <=) + + (define fl>=? >=) + + (define (flunordered? x y) + (or (nan? x) + (nan? y))) + + (define (flinteger? x) + (and (binary64? x) + (integer? x))) + + (define flzero? zero?) + + (define flpositive? positive?) + + (define flnegative? negative?) + + (define flodd? odd?) + + (define fleven? even?) + + (define flfinite? finite?) + + (define flinfinite? infinite?) + + (define flnan? nan?) + + (define flnormalized? binary64-normalized?) + + (define fldenormalized? binary64-denormalized?) + + (define flmax binary64-max) + + (define flmin binary64-min) + + (define fl+ +) + + (define fl* *) + + (define fl+* binary64-fused-multiply-add) + + (define fl- -) + + (define fl/ /) + + (define flabs binary64-abs) + + (define (flabsdiff x y) + (flabs (- x y))) + + (define (flposdiff x y) + (flmax (fl- x y) 0.0)) + + (define (flsgn x) + (flcopysign 1.0 x)) + + (define flnumerator numerator) + + (define fldenominator denominator) + + (define flfloor floor) + + (define flceiling ceiling) + + (define flround round) + + (define fltruncate truncate) + + (define flexp exp) + + (define (flexp2 x) + (expt 2 x)) + + (define flexp-1 binary64-expm1) + ) + ) diff --git a/configure/basis.cpp b/configure/basis.cpp index 2dc0cd7b1..7b8ad54c0 100644 --- a/configure/basis.cpp +++ b/configure/basis.cpp @@ -42,6 +42,7 @@ namespace meevax R"##(${srfi-78.ss})##", R"##(${srfi-98.ss})##", R"##(${srfi-111.ss})##", + R"##(${srfi-144.ss})##", R"##(${srfi-149.ss})##", }; } diff --git a/include/meevax/kernel/complex.hpp b/include/meevax/kernel/complex.hpp index 881ed95f8..108681df1 100644 --- a/include/meevax/kernel/complex.hpp +++ b/include/meevax/kernel/complex.hpp @@ -35,6 +35,8 @@ namespace meevax::inline kernel auto real() const noexcept -> object const&; + explicit operator std::complex() const; + explicit operator std::complex() const; }; diff --git a/include/meevax/kernel/number.hpp b/include/meevax/kernel/number.hpp index e317fd754..d81ae4fe7 100644 --- a/include/meevax/kernel/number.hpp +++ b/include/meevax/kernel/number.hpp @@ -248,23 +248,6 @@ inline namespace kernel auto make_number(std::string const&, int = 10) -> object; - template - auto inexact_cast(T&& x) -> decltype(auto) - { - if constexpr (std::is_same_v, complex>) - { - return std::complex(std::forward(x)); - } - else if constexpr (std::is_floating_point_v>) - { - return std::forward(x); - } - else - { - return static_cast(std::forward(x)); - } - } - template auto inexact_equals(T const& x, U const& y) { @@ -338,10 +321,6 @@ inline namespace number auto is_even(object const&) -> bool; - auto max(object const&) -> object; - - auto min(object const&) -> object; - auto abs(object const&) -> object; auto quotient(object const&, object const&) -> object; @@ -354,7 +333,7 @@ inline namespace number auto lcm(object const&, object const&) -> object; - auto sqrt(object const&) -> object; + auto square_root(object const&) -> object; auto pow(object const&, object const&) -> object; @@ -362,11 +341,15 @@ inline namespace number auto denominator(object const&) -> object; + auto load_exponent(object const&, object const&) -> object; + + auto number_to_string(object const&, int) -> object; + auto floor(object const&) -> object; - auto ceil(object const&) -> object; + auto ceiling(object const&) -> object; - auto trunc(object const&) -> object; + auto truncate(object const&) -> object; auto round(object const&) -> object; @@ -400,7 +383,11 @@ inline namespace number auto log(object const&) -> object; - auto number_to_string(object const&, int) -> object; + auto gamma(object const&) -> object; + + auto copy_sign(object const&, object const&) -> object; + + auto next_after(object const&, object const&) -> object; } // namespace number } // namespace kernel } // namespace meevax diff --git a/include/meevax/kernel/ratio.hpp b/include/meevax/kernel/ratio.hpp index fb1fe1b3b..b904b3e2d 100644 --- a/include/meevax/kernel/ratio.hpp +++ b/include/meevax/kernel/ratio.hpp @@ -46,6 +46,10 @@ namespace meevax::inline kernel auto numerator() const -> exact_integer; + explicit operator int() const; + + explicit operator float() const; + explicit operator double() const; }; diff --git a/include/meevax/memory/nan_boxing_pointer.hpp b/include/meevax/memory/nan_boxing_pointer.hpp index 5fbac3cab..df38ad2ff 100644 --- a/include/meevax/memory/nan_boxing_pointer.hpp +++ b/include/meevax/memory/nan_boxing_pointer.hpp @@ -18,9 +18,10 @@ #define INCLUDED_MEEVAX_MEMORY_NAN_BOXING_POINTER_HPP #include -#include #include +#include #include +#include #include #include @@ -232,7 +233,7 @@ namespace meevax::inline memory } else { - return os << std::fixed << std::setprecision(17) << cyan(value); + return os << std::fixed << std::setprecision(std::numeric_limits::max_digits10) << cyan(value); } } } diff --git a/src/kernel/boot.cpp b/src/kernel/boot.cpp index c37621ef5..22f0c4940 100644 --- a/src/kernel/boot.cpp +++ b/src/kernel/boot.cpp @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -429,16 +430,6 @@ namespace meevax::inline kernel define("(meevax inexact)", [](library & library) { - library.define("binary32?", [](let const& xs) - { - return std::numeric_limits::is_iec559 and car(xs).is(); - }); - - library.define("binary64?", [](let const& xs) - { - return std::numeric_limits::is_iec559 and car(xs).is(); - }); - library.define("finite?", [](let const& xs) { return is_finite(car(xs)); @@ -461,7 +452,7 @@ namespace meevax::inline kernel library.define("sqrt", [](let const& xs) { - return sqrt(car(xs)); + return square_root(car(xs)); }); library.define("log", [](let const& xs) @@ -548,6 +539,152 @@ namespace meevax::inline kernel { return atanh(car(xs)); }); + + library.define("gamma", [](let const& xs) + { + return gamma(car(xs)); + }); + + library.define("next-after", [](let const& xs) + { + return next_after(car(xs), cadr(xs)); + }); + + library.define("copy-sign", [](let const& xs) + { + return copy_sign(car(xs), cadr(xs)); + }); + + library.define("load-exponent", [](let const& xs) + { + return load_exponent(car(xs), cadr(xs)); + }); + + library.define("e", std::numbers::e); + + library.define("pi", std::numbers::pi); + + library.define("euler", std::numbers::egamma); + + library.define("phi", std::numbers::phi); + }); + + define("(meevax binary32)", [](library & library) + { + library.define("binary32?", [](let const& xs) + { + return std::numeric_limits::is_iec559 and car(xs).is(); + }); + }); + + define("(meevax binary64)", [](library & library) + { + library.define("binary64?", [](let const& xs) + { + return std::numeric_limits::is_iec559 and car(xs).is(); + }); + + library.define("binary64-least", std::numeric_limits::min()); + + library.define("binary64-greatest", std::numeric_limits::max()); + + library.define("binary64-epsilon", std::numeric_limits::epsilon()); + + #ifdef FP_FAST_FMA + library.define("FP_FAST_FMA", true); + #else + library.define("FP_FAST_FMA", false); + #endif + + library.define("binary64-integral-part", [](let const& xs) + { + auto integral_part = 0.0; + std::modf(car(xs).as(), &integral_part); + return make(integral_part); + }); + + library.define("binary64-fractional-part", [](let const& xs) + { + auto integral_part = 0.0; + return make(std::modf(car(xs).as(), &integral_part)); + }); + + library.define("binary64-log-binary", [](let const& xs) + { + return make(std::logb(car(xs).as())); + }); + + library.define("binary64-integer-log-binary", [](let const& xs) + { + return make(std::ilogb(car(xs).as())); + }); + + library.define("binary64-normalized-fraction", [](let const& xs) + { + auto exponent = 0; + return make(std::frexp(car(xs).as(), &exponent)); + }); + + library.define("binary64-exponent", [](let const& xs) + { + auto exponent = 0; + std::frexp(car(xs).as(), &exponent); + return make(exponent); + }); + + library.define("binary64-sign-bit", [](let const& xs) + { + return make(std::signbit(car(xs).as())); + }); + + library.define("binary64-normalized?", [](let const& xs) + { + return std::fpclassify(car(xs).as()) == FP_NORMAL; + }); + + library.define("binary64-denormalized?", [](let const& xs) + { + return std::fpclassify(car(xs).as()) == FP_SUBNORMAL; + }); + + library.define("binary64-max", [](let const& xs) + { + auto max = -std::numeric_limits::infinity(); + + for (let const& x : xs) + { + max = std::fmax(max, x.as()); + } + + return make(max); + }); + + library.define("binary64-min", [](let const& xs) + { + auto min = std::numeric_limits::infinity(); + + for (let const& x : xs) + { + min = std::fmin(min, x.as()); + } + + return make(min); + }); + + library.define("binary64-fused-multiply-add", [](let const& xs) + { + return make(std::fma(car(xs).as(), cadr(xs).as(), caddr(xs).as())); + }); + + library.define("binary64-abs", [](let const& xs) + { + return make(std::fabs(car(xs).as())); + }); + + library.define("binary64-expm1", [](let const& xs) + { + return make(std::expm1(car(xs).as())); + }); }); define("(meevax list)", [](library & library) @@ -947,12 +1084,26 @@ namespace meevax::inline kernel library.define("max", [](let const& xs) { - return max(xs); + if (auto iter = std::max_element(xs.begin(), xs.end(), less_than); iter != xs.end()) + { + return std::any_of(xs.begin(), xs.end(), is_inexact) ? inexact(*iter) : *iter; + } + else + { + return unspecified; + } }); library.define("min", [](let const& xs) { - return min(xs); + if (auto iter = std::min_element(xs.begin(), xs.end(), less_than); iter != xs.end()) + { + return std::any_of(xs.begin(), xs.end(), is_inexact) ? inexact(*iter) : *iter; + } + else + { + return unspecified; + } }); library.define("+", [](let const& xs) @@ -1056,12 +1207,12 @@ namespace meevax::inline kernel library.define("ceiling", [](let const& xs) { - return ceil(car(xs)); + return ceiling(car(xs)); }); library.define("truncate", [](let const& xs) { - return trunc(car(xs)); + return truncate(car(xs)); }); library.define("round", [](let const& xs) diff --git a/src/kernel/complex.cpp b/src/kernel/complex.cpp index 3f2f2f337..6a815baad 100644 --- a/src/kernel/complex.cpp +++ b/src/kernel/complex.cpp @@ -68,13 +68,52 @@ namespace meevax::inline kernel return first; } + complex::operator std::complex() const + { + assert(is_real(real())); + assert(is_real(imag())); + + auto to_int = [](let const& x) + { + if (x.is()) + { + return static_cast(x.as()); + } + else if (x.is()) + { + return static_cast(x.as()); + } + else + { + assert(x.is()); + return static_cast(x.as()); + } + }; + + return std::complex(to_int(exact(real())), + to_int(exact(imag()))); + } + complex::operator std::complex() const { assert(is_real(real())); assert(is_real(imag())); - return std::complex(inexact(real()).as(), - inexact(imag()).as()); + auto to_double = [](let const& x) + { + if (x.is()) + { + return x.as(); + } + else + { + assert(x.is()); + return static_cast(x.as()); + } + }; + + return std::complex(to_double(inexact(real())), + to_double(inexact(imag()))); } auto operator <<(std::ostream & os, complex const& z) -> std::ostream & @@ -116,7 +155,7 @@ namespace meevax::inline kernel { auto hypotenuse = [](let const& x, let const& y) { - return sqrt(x * x + y * y); + return square_root(x * x + y * y); }; return hypotenuse(real_part(x), diff --git a/src/kernel/number.cpp b/src/kernel/number.cpp index 02def90d9..8d56b547c 100644 --- a/src/kernel/number.cpp +++ b/src/kernel/number.cpp @@ -50,23 +50,23 @@ namespace meevax::inline kernel auto operator > (exact_integer const& a, ratio const& b) -> bool { return 0 > mpq_cmp_z(b.value, a.value); } auto operator >=(exact_integer const& a, ratio const& b) -> bool { return 0 >= mpq_cmp_z(b.value, a.value); } - 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; } - 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; } - auto operator % (exact_integer const& a, float b) -> float { return std::remainder(inexact_cast(a), b); } - auto operator ==(exact_integer const& a, float b) -> bool { return inexact_equals(inexact_cast(a), b); } + auto operator + (exact_integer const& a, float b) -> float { return static_cast(a) + b; } + auto operator - (exact_integer const& a, float b) -> float { return static_cast(a) - b; } + auto operator * (exact_integer const& a, float b) -> float { return static_cast(a) * b; } + auto operator / (exact_integer const& a, float b) -> float { return static_cast(a) / b; } + auto operator % (exact_integer const& a, float b) -> float { return std::remainder(static_cast(a), b); } + auto operator ==(exact_integer const& a, float b) -> bool { return inexact_equals(static_cast(a), b); } auto operator !=(exact_integer const& a, float b) -> bool { return not (a == b); } - auto operator < (exact_integer const& a, float b) -> bool { return inexact_cast(a) < b; } - auto operator <=(exact_integer const& a, float b) -> bool { return inexact_cast(a) <= b; } - auto operator > (exact_integer const& a, float b) -> bool { return inexact_cast(a) > b; } - auto operator >=(exact_integer const& a, float b) -> bool { return inexact_cast(a) >= b; } - - auto operator + (exact_integer const& a, double b) -> double { return inexact_cast(a) + b; } - auto operator - (exact_integer const& a, double b) -> double { return inexact_cast(a) - b; } - auto operator * (exact_integer const& a, double b) -> double { return inexact_cast(a) * b; } - auto operator / (exact_integer const& a, double b) -> double { return inexact_cast(a) / b; } - auto operator % (exact_integer const& a, double b) -> double { return std::remainder(inexact_cast(a), b); } + auto operator < (exact_integer const& a, float b) -> bool { return static_cast(a) < b; } + auto operator <=(exact_integer const& a, float b) -> bool { return static_cast(a) <= b; } + auto operator > (exact_integer const& a, float b) -> bool { return static_cast(a) > b; } + auto operator >=(exact_integer const& a, float b) -> bool { return static_cast(a) >= b; } + + auto operator + (exact_integer const& a, double b) -> double { return static_cast(a) + b; } + auto operator - (exact_integer const& a, double b) -> double { return static_cast(a) - b; } + auto operator * (exact_integer const& a, double b) -> double { return static_cast(a) * b; } + auto operator / (exact_integer const& a, double b) -> double { return static_cast(a) / b; } + auto operator % (exact_integer const& a, double b) -> double { return std::remainder(static_cast(a), b); } 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 < (exact_integer const& a, double b) -> bool { return mpz_cmp_d(a.value, b) < 0; } @@ -105,29 +105,29 @@ namespace meevax::inline kernel 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; } - 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; } - auto operator % (ratio const& a, float b) -> float { return std::remainder(inexact_cast(a), b); } - auto operator ==(ratio const& a, float b) -> bool { return inexact_equals(inexact_cast(a), b); } + auto operator + (ratio const& a, float b) -> float { return static_cast(a) + b; } + auto operator - (ratio const& a, float b) -> float { return static_cast(a) - b; } + auto operator * (ratio const& a, float b) -> float { return static_cast(a) * b; } + auto operator / (ratio const& a, float b) -> float { return static_cast(a) / b; } + auto operator % (ratio const& a, float b) -> float { return std::remainder(static_cast(a), b); } + auto operator ==(ratio const& a, float b) -> bool { return inexact_equals(static_cast(a), b); } auto operator !=(ratio const& a, float b) -> bool { return not (a == b); } - auto operator < (ratio const& a, float b) -> bool { return inexact_cast(a) < b; } - auto operator <=(ratio const& a, float b) -> bool { return inexact_cast(a) <= b; } - auto operator > (ratio const& a, float b) -> bool { return inexact_cast(a) > b; } - auto operator >=(ratio const& a, float b) -> bool { return inexact_cast(a) >= b; } - - auto operator + (ratio const& a, double b) -> double { return inexact_cast(a) + b; } - auto operator - (ratio const& a, double b) -> double { return inexact_cast(a) - b; } - auto operator * (ratio const& a, double b) -> double { return inexact_cast(a) * b; } - auto operator / (ratio const& a, double b) -> double { return inexact_cast(a) / b; } - auto operator % (ratio const& a, double b) -> double { return std::remainder(inexact_cast(a), b); } - auto operator ==(ratio const& a, double b) -> bool { return inexact_equals(inexact_cast(a), b); } + auto operator < (ratio const& a, float b) -> bool { return static_cast(a) < b; } + auto operator <=(ratio const& a, float b) -> bool { return static_cast(a) <= b; } + auto operator > (ratio const& a, float b) -> bool { return static_cast(a) > b; } + auto operator >=(ratio const& a, float b) -> bool { return static_cast(a) >= b; } + + auto operator + (ratio const& a, double b) -> double { return static_cast(a) + b; } + auto operator - (ratio const& a, double b) -> double { return static_cast(a) - b; } + auto operator * (ratio const& a, double b) -> double { return static_cast(a) * b; } + auto operator / (ratio const& a, double b) -> double { return static_cast(a) / b; } + auto operator % (ratio const& a, double b) -> double { return std::remainder(static_cast(a), b); } + auto operator ==(ratio const& a, double b) -> bool { return inexact_equals(static_cast(a), b); } auto operator !=(ratio const& a, double b) -> bool { return not (a == b); } - auto operator < (ratio const& a, double b) -> bool { return inexact_cast(a) < b; } - auto operator <=(ratio const& a, double b) -> bool { return inexact_cast(a) <= b; } - auto operator > (ratio const& a, double b) -> bool { return inexact_cast(a) > b; } - auto operator >=(ratio const& a, double b) -> bool { return inexact_cast(a) >= b; } + auto operator < (ratio const& a, double b) -> bool { return static_cast(a) < b; } + auto operator <=(ratio const& a, double b) -> bool { return static_cast(a) <= b; } + auto operator > (ratio const& a, double b) -> bool { return static_cast(a) > b; } + auto operator >=(ratio const& a, double b) -> bool { return static_cast(a) >= b; } auto operator + (ratio const& a, complex const& b) -> complex { return complex(make(a), e0) + b; } auto operator - (ratio const& a, complex const& b) -> complex { return complex(make(a), e0) - b; } @@ -136,29 +136,29 @@ namespace meevax::inline kernel auto operator ==(ratio const& a, complex const& b) -> bool { return complex(make(a), e0) == b; } auto operator !=(ratio const& a, complex const& b) -> bool { return complex(make(a), e0) != b; } - auto operator + (float a, exact_integer const& b) -> float { return a + inexact_cast(b); } - auto operator - (float a, exact_integer const& b) -> float { return a - inexact_cast(b); } - auto operator * (float a, exact_integer const& b) -> float { return a * inexact_cast(b); } - auto operator / (float a, exact_integer const& b) -> float { return a / inexact_cast(b); } - auto operator % (float a, exact_integer const& b) -> float { return std::remainder(a, inexact_cast(b)); } - auto operator ==(float a, exact_integer const& b) -> bool { return inexact_equals(a, inexact_cast(b)); } + auto operator + (float a, exact_integer const& b) -> float { return a + static_cast(b); } + auto operator - (float a, exact_integer const& b) -> float { return a - static_cast(b); } + auto operator * (float a, exact_integer const& b) -> float { return a * static_cast(b); } + auto operator / (float a, exact_integer const& b) -> float { return a / static_cast(b); } + auto operator % (float a, exact_integer const& b) -> float { return std::remainder(a, static_cast(b)); } + auto operator ==(float a, exact_integer const& b) -> bool { return inexact_equals(a, static_cast(b)); } auto operator !=(float a, exact_integer const& b) -> bool { return not (a == b); } - auto operator < (float a, exact_integer const& b) -> bool { return a < inexact_cast(b); } - auto operator <=(float a, exact_integer const& b) -> bool { return a <= inexact_cast(b); } - auto operator > (float a, exact_integer const& b) -> bool { return a > inexact_cast(b); } - auto operator >=(float a, exact_integer const& b) -> bool { return a >= inexact_cast(b); } - - auto operator + (float a, ratio const& b) -> float { return a + inexact_cast(b); } - auto operator - (float a, ratio const& b) -> float { return a - inexact_cast(b); } - auto operator * (float a, ratio const& b) -> float { return a * inexact_cast(b); } - auto operator / (float a, ratio const& b) -> float { return a / inexact_cast(b); } - auto operator % (float a, ratio const& b) -> float { return std::remainder(a, inexact_cast(b)); } - auto operator ==(float a, ratio const& b) -> bool { return inexact_equals(a, inexact_cast(b)); } + auto operator < (float a, exact_integer const& b) -> bool { return a < static_cast(b); } + auto operator <=(float a, exact_integer const& b) -> bool { return a <= static_cast(b); } + auto operator > (float a, exact_integer const& b) -> bool { return a > static_cast(b); } + auto operator >=(float a, exact_integer const& b) -> bool { return a >= static_cast(b); } + + auto operator + (float a, ratio const& b) -> float { return a + static_cast(b); } + auto operator - (float a, ratio const& b) -> float { return a - static_cast(b); } + auto operator * (float a, ratio const& b) -> float { return a * static_cast(b); } + auto operator / (float a, ratio const& b) -> float { return a / static_cast(b); } + auto operator % (float a, ratio const& b) -> float { return std::remainder(a, static_cast(b)); } + auto operator ==(float a, ratio const& b) -> bool { return inexact_equals(a, static_cast(b)); } auto operator !=(float a, ratio const& b) -> bool { return not (a == b); } - auto operator < (float a, ratio const& b) -> bool { return a < inexact_cast(b); } - auto operator <=(float a, ratio const& b) -> bool { return a <= inexact_cast(b); } - auto operator > (float a, ratio const& b) -> bool { return a > inexact_cast(b); } - auto operator >=(float a, ratio const& b) -> bool { return a >= inexact_cast(b); } + auto operator < (float a, ratio const& b) -> bool { return a < static_cast(b); } + auto operator <=(float a, ratio const& b) -> bool { return a <= static_cast(b); } + auto operator > (float a, ratio const& b) -> bool { return a > static_cast(b); } + auto operator >=(float a, ratio const& b) -> bool { return a >= static_cast(b); } auto operator + (float a, complex const& b) -> complex { return complex(make(a), e0) + b; } auto operator - (float a, complex const& b) -> complex { return complex(make(a), e0) - b; } @@ -167,11 +167,11 @@ namespace meevax::inline kernel auto operator ==(float a, complex const& b) -> bool { return complex(make(a), e0) == b; } auto operator !=(float a, complex const& b) -> bool { return complex(make(a), e0) != b; } - auto operator + (double a, exact_integer const& b) -> double { return a + inexact_cast(b); } - auto operator - (double a, exact_integer const& b) -> double { return a - inexact_cast(b); } - auto operator * (double a, exact_integer const& b) -> double { return a * inexact_cast(b); } - auto operator / (double a, exact_integer const& b) -> double { return a / inexact_cast(b); } - auto operator % (double a, exact_integer const& b) -> double { return std::remainder(a, inexact_cast(b)); } + auto operator + (double a, exact_integer const& b) -> double { return a + static_cast(b); } + auto operator - (double a, exact_integer const& b) -> double { return a - static_cast(b); } + auto operator * (double a, exact_integer const& b) -> double { return a * static_cast(b); } + auto operator / (double a, exact_integer const& b) -> double { return a / static_cast(b); } + auto operator % (double a, exact_integer const& b) -> double { return std::remainder(a, static_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; } @@ -179,17 +179,17 @@ namespace meevax::inline kernel 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); } - 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); } - auto operator % (double a, ratio const& b) -> double { return std::remainder(a, inexact_cast(b)); } - auto operator ==(double a, ratio const& b) -> bool { return inexact_equals(a, inexact_cast(b)); } + auto operator + (double a, ratio const& b) -> double { return a + static_cast(b); } + auto operator - (double a, ratio const& b) -> double { return a - static_cast(b); } + auto operator * (double a, ratio const& b) -> double { return a * static_cast(b); } + auto operator / (double a, ratio const& b) -> double { return a / static_cast(b); } + auto operator % (double a, ratio const& b) -> double { return std::remainder(a, static_cast(b)); } + auto operator ==(double a, ratio const& b) -> bool { return inexact_equals(a, static_cast(b)); } auto operator !=(double a, ratio const& b) -> bool { return not (a == b); } - auto operator < (double a, ratio const& b) -> bool { return a < inexact_cast(b); } - auto operator <=(double a, ratio const& b) -> bool { return a <= inexact_cast(b); } - auto operator > (double a, ratio const& b) -> bool { return a > inexact_cast(b); } - auto operator >=(double a, ratio const& b) -> bool { return a >= inexact_cast(b); } + auto operator < (double a, ratio const& b) -> bool { return a < static_cast(b); } + auto operator <=(double a, ratio const& b) -> bool { return a <= static_cast(b); } + auto operator > (double a, ratio const& b) -> bool { return a > static_cast(b); } + auto operator >=(double a, ratio const& b) -> bool { return a >= static_cast(b); } auto operator + (double a, complex const& b) -> complex { return complex(make(a), e0) + b; } auto operator - (double a, complex const& b) -> complex { return complex(make(a), e0) - b; } @@ -259,6 +259,8 @@ namespace meevax::inline kernel using complex_numbers = combination; + using real_number = std::tuple; + using real_numbers = combination; template @@ -393,23 +395,6 @@ namespace meevax::inline kernel { "-inf.0", -std::numeric_limits::infinity() }, { "+nan.0", +std::numeric_limits::quiet_NaN() }, { "-nan.0", -std::numeric_limits::quiet_NaN() }, - - // SRFI-144 - { "fl-e", M_E }, - { "fl-log2-e", M_LOG2E }, - { "fl-log10-e", M_LOG10E }, - { "fl-log-2", M_LN2 }, - { "fl-1/log-2", M_LN2 }, - { "fl-log-10", M_LN10 }, - { "fl-1/log-10", M_LN10 }, - { "fl-pi", M_PI }, - { "fl-1/pi", M_1_PI }, - { "fl-pi/2", M_PI_2 }, - { "fl-pi/4", M_PI_4 }, - { "fl-2/pi", M_2_PI }, - { "fl-2/sqrt-pi", M_2_SQRTPI }, - { "fl-sqrt-2", M_SQRT2 }, - { "fl-1/sqrt-2", M_SQRT1_2 }, }; auto static const pattern = std::regex(R"([+-]?(?:\d+\.?|\d*\.\d+)(?:([DEFdef])[+-]?\d+)?)"); @@ -557,7 +542,7 @@ inline namespace number } else { - return inexact_cast(std::forward(x)); + return static_cast(std::forward(x)); } }; @@ -732,30 +717,6 @@ inline namespace number return is_zero(remainder(x, e2)); } - auto max(object const& xs) -> object - { - if (auto iter = std::max_element(xs.begin(), xs.end(), less_than); iter != xs.end()) - { - return std::any_of(xs.begin(), xs.end(), is_inexact) ? inexact(*iter) : *iter; - } - else - { - return unspecified; - } - } - - auto min(object const& xs) -> object - { - if (auto iter = std::min_element(xs.begin(), xs.end(), less_than); iter != xs.end()) - { - return std::any_of(xs.begin(), xs.end(), is_inexact) ? inexact(*iter) : *iter; - } - else - { - return unspecified; - } - } - auto abs(object const& x) -> object { auto f = [](T const& x) @@ -772,7 +733,7 @@ inline namespace number } else if constexpr (std::is_same_v) { - return sqrt(x.real() * x.real() + x.imag() * x.imag()); + return square_root(x.real() * x.real() + x.imag() * x.imag()); } else { @@ -786,7 +747,7 @@ inline namespace number auto quotient(object const& x, object const& y) -> object { - return trunc(x / y); + return truncate(x / y); } auto remainder(object const& x, object const& y) -> object @@ -809,35 +770,35 @@ inline namespace number return abs(quotient(x * y, gcd(x, y))); } - auto sqrt(object const& x) -> object + auto square_root(object const& x) -> object { auto f = [](T const& x) { if constexpr (std::is_same_v) { - auto const z = std::sqrt(inexact_cast(x)); + auto const z = std::sqrt(static_cast>(x)); return complex(make(z.real()), make(z.imag())); } else { - auto sqrt = [](auto&& x) + auto square_root = [](auto const& x) { if constexpr (std::is_same_v) { auto const [s, r] = x.square_root(); - return r == 0 ? make(s) : make(std::sqrt(inexact_cast(x))); + return r == 0 ? make(s) : make(std::sqrt(static_cast(x))); } else { - return make(std::sqrt(inexact_cast(std::forward(x)))); + return make(std::sqrt(static_cast(x))); } }; - return x < exact_integer(0) ? make(e0, sqrt(exact_integer(0) - x)) - : sqrt(x); + return x < exact_integer(0) ? make(e0, square_root(exact_integer(0) - x)) + : square_root(x); } }; @@ -851,8 +812,20 @@ inline namespace number if constexpr (std::is_same_v or std::is_same_v) { - auto const z = std::pow(inexact_cast(std::forward(x)), - inexact_cast(std::forward(y))); + auto inexact = [](auto&& x) + { + if constexpr (std::is_same_v, complex>) + { + return static_cast>(std::forward(x)); + } + else + { + return static_cast(std::forward(x)); + } + }; + + auto const z = std::pow(inexact(std::forward(x)), + inexact(std::forward(y))); return complex(make(z.real()), make(z.imag())); @@ -866,8 +839,8 @@ inline namespace number } else { - return std::pow(inexact_cast(std::forward(x)), - inexact_cast(std::forward(y))); + return std::pow(static_cast(std::forward(x)), + static_cast(std::forward(y))); } }; @@ -910,102 +883,133 @@ inline namespace number } } - #define DEFINE(ROUND) \ - auto ROUND(object const& x) -> object \ + auto load_exponent(object const& x, object const& y) -> object + { + auto f = [](auto&& x, auto&& y) + { + return std::ldexp(static_cast(std::forward(x)), + static_cast(std::forward(y))); + }; + + return apply_to(f, x, y); + } + + auto number_to_string(object const& x, int radix) -> object + { + auto f = [radix](T const& x) + { + if constexpr (std::is_floating_point_v) + { + return string("TODO"); + } + else if constexpr (std::is_same_v) + { + return string(std::unique_ptr(mpz_get_str(nullptr, radix, x.value)).get()); + } + else + { + return string("TODO"); + } + }; + + return apply_to(f, x); + } + + #define DEFINE_EXACTNESS_PRESERVED_COMPLEX1(NAME, CMATH) \ + auto NAME(object const& x) -> object \ { \ auto f = [](T const& x) \ { \ if constexpr (std::is_floating_point_v) \ { \ - return std::ROUND(inexact_cast(std::forward(x))); \ + return CMATH(x); \ } \ else if constexpr (std::is_same_v) \ { \ - return exact_integer(std::ROUND(inexact_cast(std::forward(x)))); \ + return exact_integer(CMATH(static_cast(x))); \ } \ else if constexpr (std::is_same_v) \ { \ - return std::forward(x); \ + return x; \ } \ else \ { \ - return complex(ROUND(x.real()), \ - ROUND(x.imag())); \ + return complex(NAME(x.real()), \ + NAME(x.imag())); \ } \ }; \ \ return apply_to(f, x); \ - } \ - static_assert(true) - - DEFINE(floor); - DEFINE(ceil); - DEFINE(trunc); - DEFINE(round); + } - #undef DEFINE + DEFINE_EXACTNESS_PRESERVED_COMPLEX1(ceiling, std::ceil) + DEFINE_EXACTNESS_PRESERVED_COMPLEX1(floor, std::floor) + DEFINE_EXACTNESS_PRESERVED_COMPLEX1(round, std::round) + DEFINE_EXACTNESS_PRESERVED_COMPLEX1(truncate, std::trunc) - #define DEFINE(CMATH) \ - auto CMATH(object const& x) -> object \ + #define DEFINE_COMPLEX1(NAME, CMATH) \ + auto NAME(object const& x) -> object \ { \ auto f = [](T const& x) \ { \ if constexpr (std::is_same_v) \ { \ - auto const z = std::CMATH(inexact_cast(std::forward(x))); \ + auto const z = CMATH(static_cast>(std::forward(x))); \ \ return complex(make(z.real()), \ make(z.imag())); \ } \ else \ { \ - return std::CMATH(inexact_cast(std::forward(x))); \ + return CMATH(static_cast(std::forward(x))); \ } \ }; \ \ return apply_to(f, x); \ - } \ - static_assert(true) - - DEFINE(sin); DEFINE(asin); DEFINE(sinh); DEFINE(asinh); - DEFINE(cos); DEFINE(acos); DEFINE(cosh); DEFINE(acosh); - DEFINE(tan); DEFINE(atan); DEFINE(tanh); DEFINE(atanh); - - DEFINE(exp); - DEFINE(log); - - #undef DEFINE - - auto atan(object const& x, object const& y) -> object - { - auto f = [](auto&& x, auto&& y) - { - return std::atan2(inexact_cast(std::forward(x)), - inexact_cast(std::forward(y))); - }; + } - return apply_to(f, x, y); + DEFINE_COMPLEX1(acos, std::acos) + DEFINE_COMPLEX1(acosh, std::acosh) + DEFINE_COMPLEX1(asin, std::asin) + DEFINE_COMPLEX1(asinh, std::asinh) + DEFINE_COMPLEX1(atan, std::atan) + DEFINE_COMPLEX1(atanh, std::atanh) + DEFINE_COMPLEX1(cos, std::cos) + DEFINE_COMPLEX1(cosh, std::cosh) + DEFINE_COMPLEX1(exp, std::exp) + DEFINE_COMPLEX1(log, std::log) + DEFINE_COMPLEX1(sin, std::sin) + DEFINE_COMPLEX1(sinh, std::sinh) + DEFINE_COMPLEX1(tan, std::tan) + DEFINE_COMPLEX1(tanh, std::tanh) + + #define DEFINE_REAL1(NAME, CMATH) \ + auto NAME(object const& x) -> object \ + { \ + auto f = [](auto&& x) \ + { \ + return CMATH(static_cast(std::forward(x))); \ + }; \ + \ + return apply_to(f, x); \ } - auto number_to_string(object const& x, int radix) -> object - { - auto f = [radix](T const& x) - { - if constexpr (std::is_floating_point_v) - { - return string("TODO"); - } - else if constexpr (std::is_same_v) - { - return string(std::unique_ptr(mpz_get_str(nullptr, radix, x.value)).get()); - } - else - { - return string("TODO"); - } - }; + DEFINE_REAL1(gamma, std::tgamma) - return apply_to(f, x); + #define DEFINE_REAL2(NAME, CMATH) \ + auto NAME(object const& x, object const& y) -> object \ + { \ + auto f = [](auto&& x, auto&& y) \ + { \ + return CMATH(static_cast(std::forward(x)), \ + static_cast(std::forward(y))); \ + }; \ + \ + return apply_to(f, x, y); \ } + + DEFINE_REAL2(atan, std::atan2) + DEFINE_REAL2(copy_sign, std::copysign) + DEFINE_REAL2(next_after, std::nextafter) } // namespace number } // namespace meevax::kernel diff --git a/src/kernel/ratio.cpp b/src/kernel/ratio.cpp index c74132111..0a3774007 100644 --- a/src/kernel/ratio.cpp +++ b/src/kernel/ratio.cpp @@ -87,6 +87,16 @@ namespace meevax::inline kernel return exact_integer(mpq_numref(value)); } + ratio::operator int() const + { + return mpq_get_d(value); + } + + ratio::operator float() const + { + return mpq_get_d(value); + } + ratio::operator double() const { return mpq_get_d(value); diff --git a/test/number.ss b/test/number.ss index 347ed06a3..6b6ac8a5b 100644 --- a/test/number.ss +++ b/test/number.ss @@ -1,8 +1,10 @@ (import (scheme base) (scheme inexact) (scheme process-context) - (only (meevax inexact) binary32? binary64?) - (srfi 78)) + (only (meevax binary32) binary32?) + (only (meevax binary64) binary64?) + (srfi 78) + (srfi 144)) (check (real? 1.0e0) => #t) (check (binary32? 1.0e0) => #f) diff --git a/test/srfi-144.ss b/test/srfi-144.ss new file mode 100644 index 000000000..71d3014c8 --- /dev/null +++ b/test/srfi-144.ss @@ -0,0 +1,266 @@ +(import (scheme base) + (scheme process-context) + (srfi 78) + (srfi 144)) + +(check fl-e => 2.718281828459045) + +(check fl-1/e => 0.3678794411714423215955238) + +(check fl-e-2 => 7.38905609893065) + +(check fl-e-pi/4 => 2.1932800507380154566) + +(check fl-log2-e => 1.4426950408889634073599246810018921374266) + +(check fl-log10-e => 0.4342944819032518276511289) + +(check fl-log-2 => 0.6931471805599453094172321) + +(check fl-1/log-2 => 1.4426950408889634073599246810018921374266) + +(check fl-log-3 => 1.0986122886681096913952452) + +(check fl-log-pi => 1.144729885849400174143427) + +(check fl-log-10 => 2.3025850929940456840179915) + +(check fl-1/log-10 => 0.4342944819032518276511289189166050822944) + +(check fl-pi => 3.1415926535897932384626433832795028841972) + +(check fl-1/pi => 0.3183098861837906715377675267450287240689) + +(check fl-2pi => 6.283185307179586476925287) + +(check fl-pi/2 => 1.570796326794896619231322) + +(check fl-pi/4 => 0.7853981633974483096156608) + +(check fl-pi-squared => 9.869604401089358618834491) + +(check fl-degree => 0.0174532925199432957692369076848861271344) + +(check fl-2/pi => 0.6366197723675814) + +(check fl-2/sqrt-pi => 1.1283791670955126) + +(check fl-sqrt-2 => 1.4142135623730950488016887242096980785697) + +(check fl-sqrt-3 => 1.7320508075688772935274463415058723669428) + +(check fl-sqrt-5 => 2.2360679774997896964091736687311762354406) + +(check fl-sqrt-10 => 3.1622776601683793319988935444327185337196) + +(check fl-1/sqrt-2 => 0.7071067811865475) + +(check fl-cbrt-2 => 1.2599210498948731647672106072782283505703) + +(check fl-cbrt-3 => 1.4422495703074083823216383107801095883919) + +(check fl-4thrt-2 => 1.1892071150027210667174999705604759152930) + +(check fl-phi => 1.6180339887498948482045868343656381177203) + +(check fl-log-phi => 0.4812118250596034474977589134243684231352) + +(check fl-1/log-phi => 2.0780869212350275376013226061177957677422) + +(check fl-euler => 0.5772156649015328606065120900824024310422) + +(check fl-e-euler => 1.7810724179901979852365041031071795491696) + +(check fl-sin-1 => 0.8414709848078965066525023216302989996226) + +(check fl-cos-1 => 0.5403023058681397174009366074420766037323) + +(check fl-gamma-1/2 => 1.7724538509055160272981674833411451827975) + +(check fl-gamma-1/3 => 2.6789385347077476336556929409746776441287) + +(check fl-gamma-2/3 => 1.3541179394264004169452880281545137855193) + +(check (flonum? fl-greatest) => #t) + +(check (flonum? fl-least) => #t) + +(check (< 0.0 0.0) => #f) + +(check (< 0.0 fl-least) => #t) + +(check (flonum? fl-epsilon) => #t) + +(check (boolean? fl-fast-fl+*) => #t) + +(check (exact-integer? fl-integer-exponent-zero) => #t) + +(check (exact-integer? fl-integer-exponent-nan) => #t) + +(check (= (flonum 22/7) fl-pi) => #f) + +(check (= (flonum 333/106) fl-pi) => #f) + +(check (= (flonum 355/113) fl-pi) => #f) + +(check (= (flonum 52163/16604) fl-pi) => #f) + +(check (= (flonum 103993/33102) fl-pi) => #f) + +(check (= (flonum 104348/33215) fl-pi) => #f) + +(check (= (flonum 245850922/78256779) fl-pi) => #t) + +(check (fladjacent 0.0 1.0) (=> =) fl-least) + +(check (< 0.0 (fladjacent 0.0 1.0) fl-epsilon 1.0 (+ 1.0 fl-epsilon) fl-greatest +inf.0) => #t) + +(check (flcopysign 0.0 +inf.0) => 0.0) + +(check (flcopysign 0.0 -inf.0) => -0.0) + +(check (make-flonum 3.0 4) => 48.0) + +(call-with-values + (lambda () (flinteger-fraction 3.14)) + (lambda (integral fractional) + (check integral (=> =) 3.0) + (check fractional (=> =) 0.14))) + +(check (flexponent 48.0) => 5.0) + +(check (flexponent -48.0) => 5.0) + +(check (flinteger-exponent 48.0) => 5) + +(check (flinteger-exponent -48.0) => 5) + +(call-with-values + (lambda () (flnormalized-fraction-exponent 48.0)) + (lambda (fraction exponent) + (check fraction => 0.75) + (check exponent => 6))) + +(check (flsign-bit 3.14) => 0) + +(check (flsign-bit -3.14) => 1) + +(check (flonum? 1.0) => #t) + +(check (flonum? 1.0f0) => #f) + +(check (procedure? fl=?) => #t) + +(check (procedure? fl #t) + +(check (procedure? fl>?) => #t) + +(check (procedure? fl<=?) => #t) + +(check (procedure? fl>=?) => #t) + +(check (flunordered? 1.0 2.0) => #f) + +(check (flunordered? 1.0 +nan.0) => #t) + +(check (flinteger? 3.14) => #f) + +(check (flinteger? 1.0) => #t) + +(check (procedure? flzero?) => #t) + +(check (procedure? flpositive?) => #t) + +(check (procedure? flnegative?) => #t) + +(check (procedure? flodd?) => #t) + +(check (procedure? fleven?) => #t) + +(check (procedure? flfinite?) => #t) + +(check (procedure? flinfinite?) => #t) + +(check (procedure? flnan?) => #t) + +(check (flnormalized? 1.0) => #t) + +(check (fldenormalized? (/ fl-least 2)) => #t) + +(check (flmax) => -inf.0) + +(check (flmax 0.0) => 0.0) + +(check (flmax -1.0 0.0 1.0) => 1.0) + +(check (flmin) => +inf.0) + +(check (flmin 0.0) => 0.0) + +(check (flmin -1.0 0.0 1.0) => -1.0) + +(check (procedure? fl+) => #t) + +(check (procedure? fl*) => #t) + +(check (fl+* 2.0 3.0 4.0) => 10.0) + +(check (procedure? fl-) => #t) + +(check (procedure? fl/) => #t) + +(check (flabs -0.0) => +0.0) + +(check (flabs -inf.0) => +inf.0) + +(check (flabs +inf.0) => +inf.0) + +(check (flabsdiff 0.0 1.0) => 1.0) + +(check (flabsdiff +inf.0 -inf.0) => +inf.0) + +(check (flabsdiff -inf.0 +inf.0) => +inf.0) + +(check (flposdiff 3.0 4.0) => 0.0) + +(check (flsgn +inf.0) => 1.0) + +(check (flsgn -inf.0) => -1.0) + +(check (flsgn +0.0) => 1.0) + +(check (flsgn -0.0) => -1.0) + +(check (numerator 2.25) => 9.0) + +(check (numerator -2.25) => -9.0) + +(check (denominator 2.25) => 4.0) + +(check (denominator -2.25) => 4.0) + +(check (procedure? flfloor) => #t) + +(check (procedure? flceiling) => #t) + +(check (procedure? flround) => #t) + +(check (procedure? fltruncate) => #t) + +(check (flexp -0.0) => 1.0) + +(check (flexp 0.0) => 1.0) + +(check (flexp 1.0) => fl-e) + +(check (flexp2 -0.0) => 1.0) + +(check (flexp2 0.0) => 1.0) + +(check (flexp2 fl-log2-e) => fl-e) + +(check (fl+ 1.0 (flexp-1 fl-least)) => 1.0) + +(check-report) + +(exit (check-passed? 127))