ファイヤープロジェクト
数値計算
2004-04-28T02:10+09:00   matsu
Common Lispでいろいろな数値計算をしてみた.
整数には精度に応じて二種類ある.1ワード長に収まる整数(fixnum)とnワード長に収まる整数(bignum)である.fixnum,bignumの最小値,最大値は処理系によって決まる.fixnumの最大値と最小値は以下の大域定数で分かる.
> most-positive-fixnum 
16777215
> most-negative-fixnum 
-16777216
さらにbignumについては,私の環境では少なくともfixnumの50000乗を出力した.整数か否かはintegerpでチェックできる.
> (integerp 100)
T
> (integerp 100.0)
NIL
さらにfixnumかbignumかはtypepで調べる.
> (typep most-positive-fixnum 'fixnum)
T
> (typep (+ most-positive-fixnum 1) 'fixnum)
NIL
> (typep (+ most-positive-fixnum 1) 'bignum)
T
Common Lispでは4種類の浮動小数点がある.
short-float
1ワード長で表現できる浮動小数点.正負それぞれの最大値,最小値は以下の大域定数で分かる.
> most-positive-short-float 
1.7014s38
> most-negative-short-float 
-1.7014s38
> least-positive-short-float 
2.93874s-39
> least-negative-short-float 
-2.93874s-39
single-float
単精度浮動小数点.正負それぞれの最大値,最小値は以下の大域定数で分かる.
> most-positive-single-float 
3.4028235E38
> most-negative-single-float 
-3.4028235E38
> least-positive-single-float 
1.1754944E-38
> least-negative-single-float 
-1.1754944E-38
double-float
倍精度浮動小数点.正負それぞれの最大値,最小値は以下の大域定数で分かる.
> most-positive-double-float 
1.7976931348623157d308
> most-negative-double-float 
-1.7976931348623157d308
> least-positive-double-float 
2.2250738585072014d-308
> least-negative-double-float 
-2.2250738585072014d-308
long-float
高精度浮動小数点.正負それぞれの最大値,最小値は以下の大域定数で分かる.
> most-positive-long-float 
8.8080652584198167656L646456992
> most-negative-long-float 
-8.8080652584198167656L646456992
> least-positive-long-float 
5.676615526003731344L-646456994
> least-negative-long-float 
-5.676615526003731344L-646456994
浮動小数点数か否かはfloatpで確認できる.
> (floatp 10.0)
T
> (floatp 10)
NIL
> (floatp most-positive-short-float )
T
> (floatp most-positive-single-float )
T
> (floatp most-positive-double-float )
T
> (floatp most-positive-long-float )
T
さらに各浮動小数点数型のチェックはtypepで行う.
> (typep most-positive-short-float 'short-float)
T
> (typep most-positive-single-float 'single-float)
T
> (typep most-positive-double-float 'double-float)
T
> (typep most-positive-long-float 'long-float)
T
オーバーフロー,アンダーフローとなった場合はエラーとなり,その旨通知される.
> (* 10 most-positive-short-float )

*** - floating point overflow
> (/ least-positive-short-float 10)

*** - floating point underflow
※ ここでの大域変数の意味:mostで始まるのは絶対値が最大,leastで始まるのは絶対値が最小.positiveは正,negativeは負.そして各浮動小数点型が続く.
Common Lispでは整数で割り切れない割算は分数(ratio)となる.
> (/ 10 2)
5
> (/ 1 10)
1/10
これを小数にするには関数floatを使用する.
> (float (/ 1 10))
0.1
分数の和差積商もうまく計算できる.
> (+ 1/2 1/2)
1
> (+ 1/2 1/3)
5/6
> (- 1/2 1/3)
1/6
> (* 1/2 2/3)
1/3
> (/ 1/2 2/3)
3/4
> (/ 1/2 3/2)
1/3
分子,分母を取り出すには,それぞれ関数numeratorとdenominatorを使用する.
> (numerator (/ 5 9))
5
> (denominator (/ 5 9))
9
> (numerator 10)
10
> (denominator 10)
1
分数か否かはtypepでチェックできる.
> (typep (/ 1 2) 'ratio)
T
> (typep 1 'ratio)
NIL
> (typep (/ 1 1) 'ratio)
NIL
> (typep 0.5 'ratio)
NIL
Common Lispでは複素数もあり,#C(実数部 虚数部)の形式で表現する.
> (sqrt -1)
#C(0 1)
> (expt #C(1 1) 2)
#C(0 2)
複素数から実数部,虚数部のみを取り出す関数はそれぞれrealpart,imagpartである.
> (realpart #C(1 2))
1
> (imagpart #C(1 2))
2
> (realpart 1)
1
> (imagpart 2)
0
複素数か否かはcomplexpかtypepで確認できる.
> (complexp #C(1 2))
T
> (typep #C(1 2) 'complex)
T
> (typep #C(1 0) 'complex)
NIL
> (typep #C(1 0) 'real)
T
虚数部が0の場合は実数に変換されることに注意する.
数値を対象にした述語はたくさんあるが,そのうちいくつかを紹介する.=は引数が同じ値ならば真を返し,eqlは引数が同じ型で同じ値ならば真を返す.
> (= 1 1)
T
> (= 1 1.0)
T
> (eql 1 1)
T
> (eql 1 1.0)
NIL
=,<,>,<=,>=,/=は引数が一つだと真を返す.
> (= 1)
T
> (< 1)
T
> (<= 1)
T
> (> 1)
T
> (>= 1)
T
> (/= 1)
T
=,<,>,<=,>=は,引数が3つ以上の場合は,引数を前から順に2つづつ組み合わせて評価していく(and).例えば以下の二つは等価である.
> (= a b c)
> (and (= a b)
          (= b c))
/=に3つ以上の引数を渡した場合は,どの2つの引数の組み合わせも等しくない場合に真となる.例えば以下の二つは等価である.
> (/= a b c d)
> (and (/= a b) (/= a c) (/= a d)
          (/= b c) (/= b d) (/= c d))
零正負を判定する述語zerop,plusp,minuspがある.
> (zerop 0)
T
> (zerop 1)
NIL
> (plusp 0)
NIL
> (plusp 1)
T
> (minusp 1)
NIL
> (minusp -1)
T
さらに偶数,奇数を判定する述語evenp,oddpがある.
> (oddp 2)
NIL
> (oddp 3)
T
> (evenp 4)
T
> (evenp 5)
NIL
> (evenp 0)
T
> (oddp 0)
NIL
和積は0個以上の引数をとる.引数が0個のときは+の場合は0を,*の場合は1を返す.
> (+ )
0
> (+ 1)
1
> (+ 1 1)
2
> (+ 1 1 1)
3
> (* )
1
> (* 1)
1
> (* 1 2)
2
> (* 1 2 3)
6
差と商には一つ以上の引数が必要である.
> (- 1)
-1
> (- 1 2)
-1
> (/ 10)
1/10
> (/ 10 2)
5
> (- 1 2 3)
-4
> (/ 1 2 3)
1/6
このように(- n)は-nを返す.(/ n)は1/nを返す.1増と1減を行う関数1+,1-というものもある.
> (1+ 10)
11
> (1- 10)
9
1-は引数から1引いた値を返すことに注意(見ためが紛らわしい).さらに破壊的関数incf,decfがある.incfは引数を第二引数分増,decfは引き数を第二引数分減する.どちらも第二引数はオプションで,省略した場合は1である.
> (setf a 10)
10
> (incf a)
11
> a
11
> (incf a 10)
21
> a
21
> (decf a 5)
16
> a
16
xのn乗は(expt x n),eのn乗は(exp n)を使用する.
> (expt 2 10)
1024
> (exp 1)
2.7182817
nを底とするlogXは(log x n)である.nはオプション引数で省略するとeが設定される.
> (log 1024 2)
10
> (log (exp 10))
10.0
根はexptの第二引数を分数にすれば求まるが,平方根にはより高速なsqrtがある.
> (sqrt 1024)
32
> (expt 1024 1/2)
32
matsu(C)
Since 2002
Mail to matsu