0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Ruby向けQuadMath

Last updated at Posted at 2025-10-04

QuadMathモジュール

主にLinuxで使える4倍精度浮動小数点ライブラリであるquadmathをラップしたRuby Gemを提供します。
ずいぶん前から作っていて、晴れてGemにできた次第です。

以下でインストールできます。

$ gem install quadmath

注意: Windowsなどquadmathが収録されていないOSでは使えないと思います。

使い方

以下でrequireします。

require 'quadmath'

quadmathの数学関数をQuadMathモジュール、内部で使用するプリミティブである__float128をFloat128クラス、__complex128をComplex128クラスとしてオブジェクト化しています。
四則演算などを実装しており、プリミティブ型は数値計算ができます。

Float128('5') + Float128('6') # => 11.0
Complex128('1+1i') + Complex128('2+2i') # => (3.0+3.0i)

また、Rubyのプリミティブ型を使用して算術演算も実装しています。

Float128('5') + 1 # => 6.0
Complex128('2+1i') * 2 # => (4.0+2.0i)

数値型はRubyの仕様に合わせて(Rationalクラスなら#to_rというように)相互に変換できるよう実装しています。また、Rubyの数値プリミティブ型から四倍精度にする#to_f128#to_c128もあります。各々Float128型とComplex128型に対応します。

1.to_f128 # => 1.0
1.to_c128 #=> (1.0+0.0i)

Rationalでも相互変換を実装しています。内部で四倍精度として扱い、二倍精度における情報落ちはしないので有用です。

(1/3r).to_f128 # => 0.3333333333333333333333333333333333

二倍精度から四倍精度への変換にも対応しています。ただし(案の定)情報落ちします。

(1/3r).to_f.to_f128 #=> 0.333333333333333314829616256247391```

Complex型とComplex128型を計算する場合、返却値はFloat128型をメンバーとして持つComplex型になることには注意が必要です。

c = Complex128('1+2i') + Complex('2+2i') #=> (3.0+4.0i)
c.class # => Complex

Complex128型は(Complex型と同様に)比較できません。

Complex128::I == Complex::I # => false

QuadMathモジュールはFloat128型とComplex128型を組み合わせています。
引数の型によって使用するライブラリ関数が異なる仕様です。例えば、#sqrtの引数がFloat128の場合はsqrtq()を使い、Complex128の場合はcsqrtq()を使います。

QuadMath.sqrt(Float128('1')) # => 1.0
QuadMath.sqrt(Complex128('1')) # => (1.0+0.0i)

関数に分岐切断線(ブランチカット)がある場合、実数領域外の複素解として解釈します。

QuadMath.sqrt(-1) # => (0.0+1.0i)

仕様

Rubyの実装に合わせてライブラリ関数をラップしています。例えば#inspectquadmath_snprintf()を用いたool_quad2str()という関数で文字列変換します。

QuadMath.sqrt(2) # => 1.4142135623730950488016887242096981

ただ、精度の面で正確性に難があります。このあたりの改善方法があれば誰か教えてください。

Float128('8') # => 8.0000000000000000000000000000000004

#to_sもこの実装です。Rubyの記法に基づきます。

quadmath_snprintf()単体は#quadmath_sprintfとしてフロントエンドを用意しています。ただし、メソッド名がやや異なるので注意してください。

quadmath_sprintf("%Qf", 2) # => "2.000000"
quadmath_sprintf("%Qf", 7/10r) # => "0.700000"
quadmath_sprintf("%.*Qf", Float128::DIG, 1/3r) # => "0.333333333333333333333333333333333"
quadmath_sprintf("%.*Qf", Float128::DIG, 1.0/3.0) # => "0.333333333333333314829616256247391"
quadmath_sprintf("%.*Qf", Float128::DIG, 1.to_f128 / 3) # => "0.333333333333333333333333333333333"
width = 46; prec = 20;
quadmath_sprintf("%+-#*.*Qe", width, prec, QuadMath.sqrt(2)) # => "+1.41421356237309504880e+00                   "

プリミティブ型のインスタンス生成には、Float128型はFloat128()、Complex型はComplex128()を使用し、各々strtoflt128()をラップしています。
記法はRubyに基づきます。

Float128('1.0') # => 1.0
Float128('0x2.0p+3') # => 16.0 # 16進にも対応
Complex128('1+1i') # => (1.0+1.0i)
Complex128('2e1+3e1i') # => (20.0+30.0i)

strtoflt128()単体もそのままフロントエンドを用意しています。
第二引数はオプションspとして扱っています。

strtoflt128('inf') # => Infinity
strtoflt128('-1') # => -1.0
strtoflt128('0xdeadbeef') # => 3735928559.0
sp = '' # => ""
strtoflt128('0+1i', sp: sp) # => 0.0
sp # => "+1i"

#floor #ceil #round #truncateは各々ライブラリ関数をFloat128型のメソッドに落とし込んでいます。

Float128('8.5').floor # => 8
Float128('8.5').ceil # => 9
Float128('8.5').round # => 9
Float128('8.5').truncate # => 8

nextafterq()#next_float#prev_floatの実装に使っています。

f128 = Float128(1.0) # => 1.0
f128.next_float # => 1.0000000000000000000000000000000002
f128.prev_float # => 0.9999999999999999999999999999999999

その他の実装については、ソースコードのext/quadmathを参照してください。

リスト

以下にリストを示します。

Float128 クラスのラップされた定数のリスト:

QuadMath定数 ライブラリ
NAN nanq()
INFINITY HUGE_VALQ
MAX FLT128_MAX
MIN FLT128_MIN
EPSILON FLT128_EPSILON
DENORM_MIN FLT128_DENORM_MIN
MANT_DIG FLT128_MANT_DIG
MIN_EXP FLT128_MIN_EXP
MAX_EXP FLT128_MAX_EXP
DIG FLT128_DIG
MIN_10_EXP FLT128_MIN_10_EXP
MAX_10_EXP FLT128_MAX_10_EXP

QuadMathモジュール内のラップされた関数のリスト:

メソッド名 実数解の関数 複素数解の関数
:exp expq() cexpq()
:exp2 exp2q() ---
:expm1 expm1q() ---
:log logq() clogq()
:log2 log2q() ---
:log10 log10q() clog10q()
:log1p log1pq() ---
:sqrt sqrtq() csqrtq()
:sqrt3 cbrtq() ---
:cbrt cbrtq() ---
:sin sinq() csinq()
:cos cosq() ccosq()
:tan tanq() ctanq()
:asin asinq() casinq()
:acos acosq() cacosq()
:atan atanq() catanq()
:atan2 atan2() ---
:quadrant atan2() ---
:sinh sinhq() csinhq()
:cosh coshq() ccoshq()
:tanh tanhq() ctanhq()
:asinh asinhq() casinhq()
:acosh acoshq() cacoshq()
:atanh atanhq() catanhq()
:hypot hypotq() ---
:erf erfq() ---
:erfc erfcq() ---
:lgamma lgammaq() ---
:lgamma_r lgammaq() ---
:signgam lgammaq() ---
:gamma tgammaq() ---
:j0 j0q() ---
:j1 j1q() ---
:jn jnq() ---
:y0 y0q() ---
:y1 y1q() ---
:yn ynq() ---

QuadMathモジュール内のラップされた定数のリスト

QuadMathの定数 ライブラリの定数
E M_Eq
LOG2E M_LOG2Eq
LOG10E M_LOG10Eq
LN2 M_LN2q
LN10 M_LN10q
PI M_PIq
PI_2 M_PI_2q
PI_4 M_PI_4q
ONE_PI M_1_PIq
TWO_PI M_2_PIq
TWO_SQRTPI M_2_SQRTPIq
SQRT2 M_SQRT2q
SQRT1_2 M_SQRT1_2q

関連サイト

gcc.gnu.org/onlinedocs/libquadmath/
https://www.github.com/tribusonz-2/ruby-quadmath.git

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?