Float — 多倍長浮動小数点
目次
概要
Float は sangi の任意精度浮動小数点型である。
内部表現は (符号, 仮数部 Int, 指数部 int64_t) の 3 つ組で、
値 $x$ を次のように表す。
$$x = (-1)^{s} \times m \times 2^{e}$$
ここで $s$ は符号ビット、$m$ は多倍長整数(Int)の仮数部、$e$ は 64 ビット整数の指数部である。
精度は 10 進桁数で指定し、内部ではビット精度に変換される。
IEEE 754 に準じた丸めモード(RoundingMode)をサポートし、
NaN および Infinity は全演算で安全に伝播する。
任意精度 — 桁数に制限なし。数十万桁の計算が可能
NaN/Infinity 安全 — 特殊値は IEEE 754 と同様のセマンティクスで伝播
thread_local 定数キャッシュ — $\pi, e, \log 2$ 等の数学定数はスレッドごとにキャッシュされ、同一精度での再計算を回避
精度追跡 — 有効ビット数(effectiveBits)と要求ビット数(requestedBits)を自動管理
コンストラクタ
シグネチャ 説明
Float()デフォルト構築。値は 0
Float(int value)int から構築
Float(int64_t value)64 ビット整数から構築
Float(double value)double から構築(53 ビット精度)
Float(std::string_view str)文字列から構築(10 進)
Float(const Int& value)多倍長整数から構築(exact)
Float(const Int& mantissa, int64_t exponent, bool is_negative = false)仮数部 + 指数部から構築
Float(Int&& mantissa, int64_t exponent, bool is_negative = false)仮数部(ムーブ)+ 指数部から構築
Float(int64_t mantissa, int64_t exponent, bool is_negative = false)整数仮数部 + 指数部から構築
コピー・ムーブコンストラクタおよび代入演算子はすべて default で提供される。
int64_t と double からの代入演算子も利用可能。
特殊値ファクトリ
すべて static メンバ関数である。
シグネチャ 説明
Float positiveInfinity()$+\infty$ を返す
Float negativeInfinity()$-\infty$ を返す
Float nan()NaN を返す
Float epsilon(int precision)指定精度での機械イプシロン
Float zero(int precision)指定精度のゼロ
Float one(int precision)指定精度の 1
precision を省略すると defaultPrecision()(スレッドローカル)が使用される。
数学定数
すべて static メンバ関数で、thread_local キャッシュにより同一精度での再計算を回避する。
シグネチャ 説明 アルゴリズム
Float pi(int precision)円周率 $\pi \approx 3.1416$ Chudnovsky (binary splitting)
Float e(int precision)自然対数の底 $e \approx 2.7183$ $\sum 1/n!$ (binary splitting)
Float log2(int precision)$\ln 2 \approx 0.6931$ atanh 系列
Float log10(int precision)$\ln 10 \approx 2.3026$ atanh 系列
Float euler(int precision)Euler-Mascheroni 定数 $\gamma \approx 0.5772$ Brent-McMillan
Float catalan(int precision)Catalan 定数 $G \approx 0.9160$ Euler 級数
三角・円定数
シグネチャ 説明
Float::half_pi(int precision)$\pi/2 \approx 1.5708$
Float::quarter_pi(int precision)$\pi/4 \approx 0.7854$
Float::two_pi(int precision)$2\pi \approx 6.2832$
Float::inv_pi(int precision)$1/\pi \approx 0.3183$
Float::two_inv_pi(int precision)$2/\pi \approx 0.6366$
Float::pi_squared_over_6(int precision)$\pi^2/6 = \zeta(2) \approx 1.6449$
Float::pi_squared_over_12(int precision)$\pi^2/12 \approx 0.8225$
Float::inv_sqrt_pi(int precision)$1/\sqrt{\pi} \approx 0.5642$
Float::two_inv_sqrt_pi(int precision)$2/\sqrt{\pi} \approx 1.1284$
Float::degree(int precision)$\pi/180 \approx 0.01745$
根号定数
シグネチャ 説明
Float::sqrt2(int precision)$\sqrt{2} \approx 1.4142$
Float::sqrt3(int precision)$\sqrt{3} \approx 1.7321$
Float::sqrt5(int precision)$\sqrt{5} \approx 2.2361$
Float::inv_sqrt2(int precision)$1/\sqrt{2} \approx 0.7071$
Float::cbrt2(int precision)$\sqrt[3]{2} \approx 1.2599$
対数定数
シグネチャ 説明
Float::ln3(int precision)$\ln 3 \approx 1.0986$
Float::ln5(int precision)$\ln 5 \approx 1.6094$
Float::log2e(int precision)$\log_2 e \approx 1.4427$
Float::log10e(int precision)$\log_{10} e \approx 0.4343$
著名な定数
シグネチャ 説明
Float::phi(int precision)黄金比 $(1+\sqrt{5})/2 \approx 1.6180$
Float::lemniscate(int precision)レムニスケート定数 $\varpi \approx 2.6221$
Float::gamma14(int precision)$\Gamma(1/4) \approx 3.6256$
Float::zeta3(int precision)Apéry 定数 $\zeta(3) \approx 1.2021$
Float::zeta5(int precision)$\zeta(5) \approx 1.0369$
Float::zeta7(int precision)$\zeta(7) \approx 1.0083$
Float::glaisher(int precision)Glaisher-Kinkelin 定数 $A \approx 1.2824$
Float::khinchin(int precision)Khinchin 定数 $K \approx 2.6854$
Float::omega(int precision)$\Omega$ (Lambert $W(1)$) $\approx 0.5671$
Float::sin1(int precision)$\sin 1 \approx 0.8415$
Float::cos1(int precision)$\cos 1 \approx 0.5403$
希少な数学定数
シグネチャ 説明
Float::plastic(int precision)プラスチック数 $\approx 1.3247$
Float::twin_prime(int precision)双子素数定数 $C_2 \approx 0.6602$
Float::landau_ramanujan(int precision)Landau-Ramanujan 定数 $\approx 0.7642$
Float::meissel_mertens(int precision)Meissel-Mertens 定数 $\approx 0.2615$
Float::bernstein(int precision)Bernstein 定数 $\approx 0.2801$
Float::gauss_kuzmin(int precision)Gauss-Kuzmin-Wirsing 定数 $\approx 0.3037$
Float::feigenbaum_delta(int precision)Feigenbaum $\delta \approx 4.6692$
Float::feigenbaum_alpha(int precision)Feigenbaum $\alpha \approx 2.5029$
Float::erdos_borwein(int precision)Erdős-Borwein 定数 $\approx 1.6066$
Float::laplace_limit(int precision)Laplace limit 定数 $\approx 0.6627$
Float::soldner(int precision)Ramanujan-Soldner 定数 $\mu \approx 1.4513$
Float::backhouse(int precision)Backhouse 定数 $\approx 1.4560$
Float::porter(int precision)Porter 定数 $\approx 1.4670$
Float::lieb_square_ice(int precision)Lieb の square ice 定数 $\approx 1.5396$
Float::niven(int precision)Niven 定数 $\approx 1.7052$
Float::reciprocal_fibonacci(int precision)逆 Fibonacci 定数 $\approx 3.3599$
Float::sierpinski(int precision)Sierpiński 定数 $\approx 2.5849$
Float::mills(int precision)Mills 定数 $\approx 1.3064$
Float::dottie(int precision)Dottie 数 $\approx 0.7391$
Float::golomb_dickman(int precision)Golomb-Dickman 定数 $\approx 0.6243$
Float::salem(int precision)Salem 定数 $\approx 1.1762$
Float::cahen(int precision)Cahen 定数 $\approx 0.6434$
Float::levy(int precision)Lévy 定数 $\approx 3.2758$
Float::copeland_erdos(int precision)Copeland-Erdős 定数 $\approx 0.2357$
Float::egamma_exp(int precision)$e^{\gamma} \approx 1.7811$
コード例
Float::setDefaultPrecision(100);
Float pi = Float::pi(); // π = 3.14159265...
Float e = Float::e(); // e = 2.71828182...
Float g = Float::euler(); // γ = 0.57721566... (Euler-Mascheroni)
Float s2 = Float::sqrt2(); // √2 = 1.41421356...
精度制御
シグネチャ 説明
Float& setPrecision(int precision)有効桁数を設定(丸め処理あり)。自身への参照を返す
int precision() const現在の有効桁数を取得
int effectiveBits() const信頼できるビット数を取得
int requestedBits() const目標ビット数を取得
void truncateToApprox(int precision)ワード単位の高速近似切り詰め(中間計算用)
static int precisionToBits(int precision)10 進桁数 → ビット数
static int bitsToPrecision(int bits)ビット数 → 10 進桁数
static int defaultPrecision()スレッドローカルのデフォルト精度を取得
static void setDefaultPrecision(int precision)スレッドローカルのデフォルト精度を設定
丸めモード
enum class RoundingMode {
ToNearest, // 最も近い値に丸め(デフォルト)
TowardZero, // ゼロ方向に丸め(切り捨て)
TowardPositive, // 正の無限大方向に丸め(切り上げ)
TowardNegative, // 負の無限大方向に丸め(切り下げ)
AwayFromZero // ゼロから遠ざかる方向に丸め
};
シグネチャ 説明
static RoundingMode roundingMode()現在の丸めモードを取得
static void setRoundingMode(RoundingMode mode)丸めモードを設定
状態確認
シグネチャ 説明
bool isNaN() constNaN なら true
bool isInfinity() const$\pm\infty$ なら true
bool isZero() constゼロなら true
bool isNegative() const負なら true
bool isPositive() const非負なら true(!isNegative())
bool isExact() const整数由来の正確な値なら true
bool isInteger() const整数値なら true(NaN/Infinity は false)
bool fitsInt() constint 範囲に収まるか
bool fitsInt64() constint64_t 範囲に収まるか
bool fitsDouble() constdouble 範囲に収まるか
算術演算子
シグネチャ 説明
Float operator+(const Float&, const Float&)加算
Float operator-(const Float&, const Float&)減算
Float operator*(const Float&, const Float&)乗算
Float operator/(const Float&, const Float&)除算
Float operator/(const Float&, int64_t)整数除算(高速パス)
Float& operator+=(const Float&)加算代入
Float& operator-=(const Float&)減算代入
Float& operator*=(const Float&)乗算代入
Float& operator/=(const Float&)除算代入
Float operator-(const Float&)単項マイナス(符号反転)
Float operator<<(const Float&, int)左シフト($\times 2^n$)
Float operator>>(const Float&, int)右シフト($\div 2^n$)
精度伝播ポリシー(デフォルト: MAX_PROPAGATION)に基づき、
結果の requestedBits は max(lhs, rhs)、
effectiveBits は min(lhs, rhs) となる。
比較演算子
シグネチャ 説明
bool operator==(const Float&, const Float&)等価比較
std::partial_ordering operator<=>(const Float&, const Float&)三方比較(C++20)
三方比較演算子により !=, <, >, <=, >= が自動生成される。
NaN が含まれる比較はすべて std::partial_ordering::unordered を返す(IEEE 754 準拠)。
基本数学関数
すべて sangi 名前空間のフリー関数である。
precision 引数は 10 進桁数で、計算の作業精度を指定する。
ムーブ版オーバーロードも提供されるが、表では省略する。
指数・対数
シグネチャ 説明
Float exp(const Float& x, int precision)$e^x$
Float exp2(const Float& x, int precision)$2^x$
Float exp10(const Float& x, int precision)$10^x$
Float expm1(const Float& x, int precision)$e^x - 1$($x \approx 0$ で高精度)
Float log(const Float& x, int precision)$\ln x$(AGM 法)
Float log2(const Float& x, int precision)$\log_2 x$
Float log10(const Float& x, int precision)$\log_{10} x$
Float log1p(const Float& x, int precision)$\ln(1+x)$($x \approx 0$ で高精度)
Float logUi(unsigned long long n, int precision)整数の対数(素因数分解経由で高精度)
三角関数
シグネチャ 説明
Float sin(const Float& x, int precision)$\sin x$
Float cos(const Float& x, int precision)$\cos x$
Float tan(const Float& x, int precision)$\tan x$
Float sinPi(const Float& x, int precision)$\sin(\pi x)$(整数点で正確に 0)
Float cosPi(const Float& x, int precision)$\cos(\pi x)$
Float tanPi(const Float& x, int precision)$\tan(\pi x)$
Float sec(const Float& x, int precision)$\sec x = 1/\cos x$
Float csc(const Float& x, int precision)$\csc x = 1/\sin x$
Float cot(const Float& x, int precision)$\cot x = \cos x/\sin x$
コード例
int prec = 50;
Float x("0.5", prec);
Float s = sin(x, prec); // sin(0.5)
Float c = cos(x, prec); // cos(0.5)
Float t = tan(x, prec); // tan(0.5)
逆三角関数
シグネチャ 説明
Float asin(const Float& x, int precision)$\arcsin x$
Float acos(const Float& x, int precision)$\arccos x$
Float atan(const Float& x, int precision)$\arctan x$(Taylor + 引数半減)
Float atan2(const Float& y, const Float& x, int precision)$\mathrm{atan2}(y, x)$
Float asinPi(const Float& x, int precision)$\arcsin(x) / \pi$
Float acosPi(const Float& x, int precision)$\arccos(x) / \pi$
Float atanPi(const Float& x, int precision)$\arctan(x) / \pi$
コード例
int prec = 50;
Float x("0.5", prec);
Float a = asin(x, prec); // arcsin(0.5) = π/6
Float b = acos(x, prec); // arccos(0.5) = π/3
Float c = atan(x, prec); // arctan(0.5) = 0.4636...
双曲線関数
シグネチャ 説明
Float sinh(const Float& x, int precision)$\sinh x$
Float cosh(const Float& x, int precision)$\cosh x$
Float tanh(const Float& x, int precision)$\tanh x$
Float sech(const Float& x, int precision)$\mathrm{sech}\,x = 1/\cosh x$
Float csch(const Float& x, int precision)$\mathrm{csch}\,x = 1/\sinh x$
Float coth(const Float& x, int precision)$\coth x = \cosh x/\sinh x$
コード例
int prec = 50;
Float x("1.0", prec);
Float s = sinh(x, prec); // sinh(1) = 1.1752...
Float c = cosh(x, prec); // cosh(1) = 1.5430...
Float t = tanh(x, prec); // tanh(1) = 0.7615...
逆双曲線関数
シグネチャ 説明
Float asinh(const Float& x, int precision)$\mathrm{arcsinh}\,x$
Float acosh(const Float& x, int precision)$\mathrm{arccosh}\,x$
Float atanh(const Float& x, int precision)$\mathrm{arctanh}\,x$
冪乗・根
シグネチャ 説明
Float sqr(const Float& x, int precision)$x^2$(二乗、最適化アルゴリズム使用)
Float pow(const Float& x, const Float& y, int precision)$x^y$
Float pow(const Float& x, int n, int precision)$x^n$(整数冪、二分累乗法)
Float sqrt(const Float& x, int precision)$\sqrt{x}$
Float cbrt(const Float& x, int precision)$\sqrt[3]{x}$
Float nthRoot(const Float& x, int n, int precision)$\sqrt[n]{x}$
Float recSqrt(const Float& x, int precision)$1/\sqrt{x}$(逆平方根)
Float hypot(const Float& x, const Float& y, int precision)$\sqrt{x^2 + y^2}$(オーバーフロー安全)
コード例
int prec = 50;
Float x("2.0", prec);
Float s = sqrt(x, prec); // √2 = 1.41421356...
Float c = cbrt(x, prec); // ∛2 = 1.25992104...
Float p = pow(x, Float("0.5", prec), prec); // 2^0.5 = √2
その他
シグネチャ 説明
Float abs(const Float& x)$|x|$
Float fma(const Float& a, const Float& b, const Float& c, int precision)$ab + c$(融合積和)
Float fms(const Float& a, const Float& b, const Float& c, int precision)$ab - c$(融合積差)
Float fmma(const Float& a, const Float& b, const Float& c, const Float& d, int precision)$ab + cd$(二重融合積和)
Float fmms(const Float& a, const Float& b, const Float& c, const Float& d, int precision)$ab - cd$(二重融合積差)
Float factorial(int n, int precision)$n!$
void sinCos(const Float& x, Float& s, Float& c, int precision)$\sin x$ と $\cos x$ を同時計算
void sinhCosh(const Float& x, Float& s, Float& c, int precision)$\sinh x$ と $\cosh x$ を同時計算
Float agm(const Float& a, const Float& b, int precision)算術幾何平均 $\mathrm{AGM}(a, b)$
Float sum(std::span<const Float> values, int precision)高精度総和
Float dot(std::span<const Float> a, std::span<const Float> b, int precision)高精度内積
誤差関数・ガンマ関数
シグネチャ 説明
Float erf(const Float& x, int precision)誤差関数 $\mathrm{erf}(x)$
Float erfc(const Float& x, int precision)相補誤差関数 $\mathrm{erfc}(x) = 1 - \mathrm{erf}(x)$
Float erfcx(const Float& x, int precision)スケール付き相補誤差関数 $e^{x^2}\,\mathrm{erfc}(x)$
Float gamma(const Float& x, int precision)$\Gamma(x)$
Float lnGamma(const Float& x, int precision)$\ln\Gamma(x)$
Float beta(const Float& a, const Float& b, int precision)$B(a, b) = \Gamma(a)\Gamma(b)/\Gamma(a+b)$
Float digamma(const Float& x, int precision)$\psi(x) = \Gamma'(x)/\Gamma(x)$
Float trigamma(const Float& x, int precision)$\psi'(x)$
Float polygamma(int n, const Float& x, int precision)$\psi^{(n)}(x)$
Float gammaP(const Float& a, const Float& x, int precision)正規化下側不完全ガンマ $P(a,x)$
Float gammaQ(const Float& a, const Float& x, int precision)正規化上側不完全ガンマ $Q(a,x)$
Float gammaLower(const Float& a, const Float& x, int precision)下側不完全ガンマ $\gamma(a,x)$
Float gammaUpper(const Float& a, const Float& x, int precision)上側不完全ガンマ $\Gamma(a,x)$
コード例
int prec = 50;
Float x("1.0", prec);
Float e = erf(x, prec); // erf(1) = 0.84270079...
Float g = gamma(x, prec); // Γ(1) = 1
Float lg = lnGamma(Float("10", prec), prec); // ln(9!) = 12.8018...
丸め・整数部
すべて sangi 名前空間のフリー関数。ムーブ版オーバーロードも提供される。
シグネチャ 説明
Float floor(const Float& x)$\lfloor x \rfloor$(床関数)
Float ceil(const Float& x)$\lceil x \rceil$(天井関数)
Float round(const Float& x)最近接丸め(half-away-from-zero: tie で 0 から遠い側)
Float roundEven(const Float& x)最近接偶数丸め(banker's rounding: tie で偶数側)
Float trunc(const Float& x)ゼロ方向への切り捨て
Float frac(const Float& x)小数部 $x - \lfloor x \rfloor$
Float nearbyint(const Float& x)round と同等
Float rint(const Float& x)round と同等
Float modf(const Float& x, Float& iptr)整数部を iptr に、小数部を返す
Float fmod(const Float& x, const Float& y)浮動小数点剰余 $x - \mathrm{trunc}(x/y) \cdot y$
Float remainder(const Float& x, const Float& y)IEEE 754 剰余 $x - \mathrm{roundEven}(x/y) \cdot y$
std::pair<Float, int> remquo(const Float& x, const Float& y)remainder + 商の符号付き下位 3 ビット
Float ldexp(const Float& x, int exp)$x \times 2^{\mathrm{exp}}$
Float frexp(const Float& x, int* exp)仮数部 $[0.5, 1)$ と指数を分離
Float scalbn(const Float& x, int n)ldexp と同等
int64_t ilogb(const Float& x)$\lfloor \log_2 |x| \rfloor$
Float logb(const Float& x)$\lfloor \log_2 |x| \rfloor$(Float 型で返す)
ユーティリティ
シグネチャ 説明
Float fmin(const Float& a, const Float& b)NaN を無視した最小値
Float fmax(const Float& a, const Float& b)NaN を無視した最大値
Float fdim(const Float& a, const Float& b)$\max(a - b, 0)$
Float copySign(const Float& x, const Float& y)$y$ の符号を $x$ にコピー
bool signBit(const Float& x)負なら true
Float nextAbove(const Float& x)$x$ より大きい最小の表現可能値
Float nextBelow(const Float& x)$x$ より小さい最大の表現可能値
Float lerp(const Float& a, const Float& b, const Float& t, int precision)線形補間 $a + t(b - a)$
Float midpoint(const Float& a, const Float& b)中点 $(a + b) / 2$
void swap(Float& a, Float& b) noexceptスワップ
文字列変換
シグネチャ 説明
std::string toString(int precision = -1) const10 進科学表記 (3.14e+0)
std::string toString(int base, int fracDigits) constN 進数表示 (2〜36 進)。toString(2, 8) → "11.01010101"、toString(16, 4) → "3.243f"
std::string toDecimalString(int precision = -1) const10 進固定小数点表記
std::string toScientificString(int precision = -1) const科学表記 ($1.23 \times 10^4$ 形式)
double toDouble() constdouble に変換(精度損失の可能性あり)
Int toInt() constInt に変換(小数部切り捨て)
ostream& operator<<(ostream&, const Float&)ストリーム出力
istream& operator>>(istream&, Float&)ストリーム入力
内部アクセス
シグネチャ 説明
const Int& mantissa() const仮数部(多倍長整数)への参照
int64_t exponent() const指数部(2 進指数)
bool isNegative() const符号フラグ
int bitLength() const仮数部のビット長
使用例
Pi の計算
#include <math/core/mp/Float.hpp>
using namespace sangi;
// 1000 桁の円周率を計算(Chudnovsky アルゴリズム)
Float::setDefaultPrecision(1000);
Float pi = Float::pi(1000);
std::cout << pi.toDecimalString(1000) << std::endl;
// 3.14159265358979323846264338327950288419716939937510...
exp / log の多倍長演算
#include <math/core/mp/Float.hpp>
using namespace sangi;
int prec = 30;
Float::setDefaultPrecision(prec);
Float x("1.5");
Float ex = exp(x, prec); // e^1.5
Float lx = log(ex, prec); // ln(e^1.5) = 1.5
std::cout << "exp(1.5) = " << ex.toDecimalString(prec) << std::endl;
std::cout << "log(exp(1.5)) = " << lx.toDecimalString(prec) << std::endl;
// 30 桁精度で完全に 1.5 に一致
NaN / Infinity の安全な伝播
Float inf = Float::positiveInfinity();
Float nan = Float::nan();
Float z = Float::zero();
Float r1 = inf + Float(1); // +Inf
Float r2 = inf - inf; // NaN
Float r3 = nan + Float(42); // NaN
Float r4 = Float(1) / z; // +Inf
std::cout << r1.isInfinity() // true
<< r2.isNaN() // true
<< r3.isNaN() // true
<< r4.isInfinity(); // true
精度制御と定数キャッシュ
// thread_local キャッシュにより、同一精度での再呼び出しは高速
Float pi1 = Float::pi(500); // 初回: 計算
Float pi2 = Float::pi(500); // 2 回目: キャッシュから即時返却
Float pi3 = Float::pi(1000); // 精度が異なるため再計算
// 丸めモードの変更
Float::setRoundingMode(RoundingMode::TowardZero);
Float x("1.999");
x.setPrecision(3); // TowardZero で丸め
関連する数学的背景
以下の記事では、Float クラスの基盤となる数学的概念を解説している。
IEEE 754 との相違点
sangi の Float は任意精度浮動小数点であり、IEEE 754 の固定幅フォーマット (float/double) とは設計目標が異なる。
IEEE 754 で定義される概念のうち、Float がサポートする範囲と意図的に省略している部分を以下に示す。
IEEE 754 の機能 sangi Float の対応 備考
5 つの丸めモード
実装済み
setRoundingMode() でスレッドごとに切替可能。
guard bit + sticky bit による正確な丸め判定を行う
NaN / ±Infinity
完全対応
生成・伝播・比較セマンティクスを実装
符号付きゼロ (±0)
表現可能
ただし x - x は常に +0 を返す。IEEE 754 では roundTowardNegative 時に -0 を返すが、Float ではこの区別を行わない
非正規化数 (subnormal)
該当なし
IEEE 754 の非正規化数はケチビット (implicit leading 1) を前提とする概念である。
Float は仮数部を Int で全ビット明示格納するため、ケチビットが存在せず、非正規化数という状態自体が発生しない。
また指数範囲が ±260 と広いため、通常の使用でアンダーフローも起きない。
subnormalize() は MPFR 互換のエミュレーション機能として提供されている
例外フラグ
基盤のみ
FE_INEXACT 等のフラグ定義は存在するが、算術演算子からは発火しない。
subnormalize() 内でのみ使用される
丸め戦略: 演算ごとの設計
IEEE 754 (および MPFR) では全演算が target precision に丸めた結果を返す。
sangi の Float は演算の種類に応じて丸めの戦略を変えている。
演算 丸め 設計意図
乗算 / 除算
requested_bits_ で丸め
同じビット数の仮数部同士の乗算では結果のビット数がほぼ 2 倍になるため、丸めなしではコストが指数的に増加する
加算 / 減算
丸めなし
加算で仮数部が伸びるのは指数差の分だけであり、伸びた下位ビットは後続演算のガードビットとして機能する。
毎回丸めるとガードビットが失われ、長い加算列で丸め誤差が蓄積する。
指数差が max(requested_bits, 1000) + 64 を超える場合は小さい方のオペランドを無視するため、
仮数部の無制限な膨張は起きない
setPrecision()
指定精度で丸め
ユーザーが明示的に精度を指定する。加算後に精度を揃えたい場合に使用する
この設計により、(a + b) * c のような式では加算の余剰ビットがガードビットとして乗算の精度を高め、
MPFR 方式(全演算で丸め)よりも同じ requested_bits_ で高い精度が得られる場合がある。
MPFR 方式で同等の精度を得るには working precision を余分に確保する必要がある。
他の多倍長ライブラリとの精度管理方式の比較
ライブラリ 精度管理方式
MPFR
結果変数に固定精度を設定し、全演算がその精度で correct rounding を行う
GMP (mpf)
結果変数に精度を設定。丸めモードの保証はない
Arb (FLINT)
ボール演算 (中心値 ± 誤差半径)。全演算で誤差半径を厳密に追跡する
mpmath (Python)
グローバル精度 (mp.prec)。全演算がその精度で丸める
sangi Float
要求精度 (requested_bits_) と有効精度 (effective_bits_) の 2 値で管理。
乗除算は要求精度で丸め、加減算はガードビットを保持して後続演算の精度を高める
← sangi トップ