数値計算
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 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) 91-は引数から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.7182817nを底とする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