Gauche:Bugsから移動
OsN (2007/03/15 01:43:38 PDT): 勘違いしているかもしれませんが、、、
gosh> (floor 10.5) 10.0
floor, ceiling, truncate, round は integer を返す、とドキュメントに ありますので、(floor 10.5) で 10 でなく、10.0 が返ってくるのが違和感あります。
Shiro(2007/03/15 02:28:08 PDT): 10.0はintegerですよ。非正確数ではありますが。 ちなみに正確数を渡せば正確なintegerが返ります。
gosh> (floor 21/2) 10
逆に、整数を要求する手続きに非正確な整数を渡せば非正確な結果が得られます:
gosh> (gcd 60.0 24.0) 12.0
多くの算術関数は、引数に非正確数が含まれる場合は非正確数で 結果を返し、引数が正確数で結果も正確数で表現可能な場合は正確数を返します。
切り捨て後に正確なintegerが欲しい場合は (inexact->exact (floor 10.5)) などと する必要があります。ただ、このような組み合わせは頻繁に使うので、0.8.10からは floor->exact 等の手続きが追加されます。
OsN (2007/03/15 03:42:36 PDT) :非正確数、、、勉強しなおしてまいりますです。ただ、非正確な整数という表現は世間一般にはない、ですよね?普通の言葉の顔をした専門用語って、嫌いだぁ。(勉強不足の言い訳)計算機の中での実数が”正確”でないことがある、というのは、多少計算をやっている人には常識でしょうけど、正確でない整数なんて、、、
くどいようで申し訳ありませんが、"10.0" という表記が整数を意味する、というのは、計算機科学では常識的な表現なんですね? (聞かぬは一生の恥ということで、、、)
Shiro(2007/03/15 04:51:40 PDT): 3つくらいトピックが混ざっているのでひとつづつ。
まず、数値に正確数(exact number)と非正確数(inexact number)がある、というのはScheme/Common Lisp界隈以外では あまり採用されていないモデルかもしれません。 これは整数かどうかとは別で、フル仕様によれば「正確な実数」 「正確な複素数」「不正確な有理数」等も存在し得ます。R5RSでは数値のこのへんの 話はオプショナルなので、Gaucheでは正確な複素数は採用していませんが。 (浮動小数点数は正確でないというイメージがありますが、それは 浮動小数点数の演算に一般的にそういうモデルを採用している、というだけです。 ひとつの浮動小数点数を取れば、それが表現する「正確な値」は存在します。 あとは解釈の問題で、それをピンポイントの正確な値と見るか、幅を持った値と 見るかってだけの話です。同様に、整数型で表現される値が正確か非正確かってのも モデルあるいは解釈の問題になります。)
表記については、Schemeの正式な表記法では正確数を#eプレフィクスで、 不正確数を#iプレフィクスで表すことになっています。ただ、全ての出力に プレフィクスをつけるのはかなり見づらいわけです。Gaucheでは浮動小数点数 が不正確数の表現に使われているので、プレフィクス無しの10.0を読み込めば 自動的に不正確な整数になってくれるという前提のもとに、出力時も#iを 付加しないで表記してます。なお読み込み時にプレフィクスをつければ この通り:
gosh> #e10.0 10 gosh> #i10 10.0 gosh> #e3.14 157/50 gosh> #i1/3 0.3333333333333333
最後に、10.0を「整数」と呼ぶことに違和感があるのは、「整数」と「整数型」とを 混同しているからではありませんか? 計算機では伝統的に、小数点を一番右に置いた固定小数点表現を用いる型を 整数型(integer型)と呼んで来ましたが、 それは単に整数の表現に特化した型であるというだけであって、 数としての「整数」はその型だけでしか表現できないというわけではありません。 (数の表現が32bit浮動小数点数しかない、というスクリプト言語を扱ったことが ありますが、そういう言語では「整数」は使えない、なんてことは無いですよね)
OsN(2007/03/15 07:44:25 PDT): ありがとうございました。python では、
>>> 0.1 0.10000000000000001
となったり、gosh では、
gosh> #i0.1 0.1 gosh> #e0.1 1/10
となるのを眺めて、正確/非正確に思いを馳せて(大げさ)おりました。整数だから正確、とは言えない計算機モデルだってあってもいいわけですね。(メリットがあるのかは別にして。)
また、最後の「整数」と「整数型」との混同では、との御指摘は、最初、単に 10.0 という表記が整数と呼ばれるのを目にするのが初めてという経験のなさ故、と思ったのですが、では、10.0 という表記をどう使ってきたか、というと、その数を単なる整数でなく実数として扱う目印にしていたに過ぎない、ということに思いあたりまして、数と型の混同と言われている意味がわかった気がしました。
Shiro(2007/03/15 12:29:19 PDT): もう少し整理してみますね。
Gauche上では、こうなる。
gosh> (integer? 3) #t gosh> (real? 3) #t gosh> (integer? 9/3) #t gosh> (real? 9/3) #t gosh> (integer? 3.0) #t gosh> (real? 3.0) #t gosh> (integer? 3.14) #f gosh> (real? 3.14) #t gosh> (integer? 157/50) #f gosh> (real? 157/50) #t
一方、Gaucheで「型」にあたるものはクラスだが、それはこの通り異なる:
gosh> (class-of 3) #<class <integer>> gosh> (class-of 3.0) #<class <real>> gosh> (class-of 157/50) #<class <rational>>
(数値は常に最も単純な型に暗黙的に変換されるので、9/3と書くと <integer>クラスのインスタンス3になる)
OsN (2007/03/20 23:23:42 PDT):丁寧な説明ありがとうございました。
私が混乱した"背景"を振り返ってみると、
Shiro(2007/03/21 00:44:32 PDT): ふむ。ドキュメントは、うっかり用語を混同している ことがあるかもしれません。今度気をつけてみてみます。
class <integer> は確かに紛らわしいんです。あと、数値のクラス階層は 実装継承になっていない(cf. Gauche:NumericTower) という問題も ありまして、いつか整理したいとは思っているんですが。
で、整数型ってどんな場面で必要? って話ですが、確かにあらゆる数値が 無限の精度で計算出来て計算コストも同じであれば、わざわざ整数に特化した 型を持つ意味はありません。現実の計算機には制約があるため、用途に 応じて特殊化された型をいくつか用意して、プログラマが必要な場合には 意識して使い分けないとならないことになっています。
Gaucheにおいては、整数型には(1)整数の演算において誤差が全く でないことが保証される(2)小さな数の範囲(32bit CPUでは30bit符号つき 整数に収まる数)での演算は非常に速い、しかしそれを越えた範囲になると 一気に遅くなる、という特徴があります。一方浮動小数点型には、 (1)広い範囲の数値において速度が概ね速い (2)しかし計算誤差が発生する 可能性がある、という特徴があり、用途に応じて使い分けるわけです。
gosh> (expt 2 256) 115792089237316195423570985008687907853269984665640564039457584007913129639936 gosh> (expt 2.0 256) 1.157920892373162e77
正確/非正確という属性については整数型とは直交する話で、例えば整数型 オブジェクトに正確/非正確のフラグつけるというような実装も考えられます。 これらは意味的な違いです---非正確な整数は、それが非正確な数の演算によって 生じたものであり、実は誤差を含むかもしれない、ということを暗示します。 (例えばIEEE倍精度浮動小数点数では結果の絶対値が2^53=9007199254740992以上 になれば必ず整数になります。小数部を表すのにビットが足りないからです)
OsN (2007/03/21 05:41:51 PDT):再び、ありがとうございました。
そうか、有効桁数(と言っていいのかな。取り扱える値の範囲)との関係があったんですね。ドキュメントには
多倍長の正確な整数 メモリの許す限りの精度が扱えます。
とちゃんと書いてあったのに、見てたようで見てませんでした。失礼しました。 (なお、上記で引用したドキュメントの記述例はそこがおかしい、という意味ではありません。念のため。)
Tag: 数値