5

2 つの非常に大きな数に対して単純な減算演算を実行しようとしています。

(- 1.8305286640724363e+023 (floor 1.8305286640724363e+023))

これを行うと、0.0 という結果が得られます。私は次の出力を期待しています:

(- 1.8305286640724363e+023 (floor 1.8305286640724363e+023)) => .2439521

拡張された科学表記法がその答えを教えてくれます。

183052866407243622723319.24395251 - 183052866407243622723319.00 = .2439521

これらの数値を、科学表記法ではなく 10 進数を使用してそのまま表現したいので、目的の結果を得ることができます。スキーム内でこれを行う方法はありますか? ヘルプ、ガイダンス、またはリファレンスをいただければ幸いです:)

DrRacket for Windows 64bit と R5RS Language を使用しています。

編集

私が実行している算術の例について、できるだけ具体的に説明したいと思います。

算術:

(* 271979577247970257395 0.6180339887) => 1.6809262297150285e+020

これと同じ掛け算を電卓で行うと、結果は => 168092622971502827156.7975214365 になります。

正確または不正確を使用しようとすると、次のようになります。

(exact (* 271979577247970257395 0.6180339887)) => exact: undefined;
(inexact (* 271979577247970257395 0.6180339887)) => inexact: undefined;

R5RS は正確/不正確をサポートしていないと思いますか? 私はそれを調べて、例は不正確->正確な手順を使用することを示しているので、私はそうしてこれを得ました:

(inexact->exact (* 271979577247970257395 0.6180339887)) => 168092622971502854144

そして、具体的に言うと、私は反対のことをしました:

(exact->inexact (* 271979577247970257395 0.6180339887)) => 1.6809262297150285e+020

それで、誰かが言ったように Big Float を使ってみました:

(bf-precision 128)
(bf (* 271979577247970257395 0.6180339887)) => (bf 168092622971502854144)

正確と同じ出力が得られます。私が単に望んでいるのは、電卓から得られる数値を保存することだけであり、それは非常に難しい作業のようです! これを理解していないのは愚かに聞こえるかもしれませんが、申し訳ありませんが、私は SCHEME の極端なアマチュアであることを覚えておいてください。ご協力いただきありがとうございます。:)

4

2 に答える 2

4

もちろん、Scheme を使用すると、正確な数値が得られます。

(define x (+ (exact 183052866407243622723319) (exact .24395251)))
(define y (+ (exact 183052866407243622723319) (exact .0)))

私は分割xして、Scheme リーダーが値を切り捨てないようにしました。それで:

> x
3297587283763054256749149618043779713285/18014398509481984
> (- x y)
4394657732528389/18014398509481984
> (inexact (- x y))
0.24395251

[編集] 計算全体を通して正確な数値を使用する必要があります。つまり、入力を正確に変換し、最後に出力を不正確に変換します (必要な場合)。

あなたの試みについては、式ではなく数値に適用される#e(* 27... 0.6...)ため、機能しません。#e使用して(* #e27... #e0.6...)ください。

> (* #e271979577247970257395 #e0.6180339887)
336185245943005654313595042873/2000000000
于 2013-04-15T14:50:57.263 に答える
4

問題は、Racket が内部表現で使用するよりも多くの有効数字が入力に含まれていることです。

裸の数字を入力しましょう:

> 183052866407243622723319.24395251
1.8305286640724363e+23

> 183052866407243622723319.00
1.8305286640724363e+23

したがって、両方の数値は内部的に同じ (整数) 数値として表されます。これは、結果が 0 だった理由を説明しています。

この動作は Racket に限定されません。実際、Racket は 64 ビット浮動小数点数を計算するための IEEE 標準に準拠しています。他のプログラミング言語でも同じ結果が得られます。

より高い精度の理由を計算する必要がある場合は、代わりに bigfloats を使用できます。

(require math/bigfloat)
(bf-precision 128) ; use 128 bits
(bf- (bf #e183052866407243622723319.24395251)
     (bfround (bf #e183052866407243622723319.00)))

結果は次のとおりです: (bf #e0.2439525099999997337363311089575290679932)

注: bigfloats を使用するには、Racket の最新バージョンを使用していることを確認してください。

更新: なぜ結果が .2439521 でなかったのか疑問に思っている場合、答えは、結果と .2439521 が同じ内部ビットパターンで表されているということです。

アップデート:

結果を標準の浮動小数点に戻したい場合は、 を使用しますbigfloat->flonum

(bf-precision 256)  ; to get more decimal digits correct
(bigfloat->flonum
   (bf- (bf #e183052866407243622723319.24395251)
        (bfround (bf #e183052866407243622723319.00))))

これにより結果が得られます: 0.24395251

補遺:

Racket (および Scheme) は、小数点を含む数値を浮動小数点数として読み取ります。数値の前に #e を付けると、正確な数値として読み取られます (つまり、結果の値は正確な分数になります)。これを使用して、正確な小数を保持できます。計算全体で数値を正確に計算し、最後に使用exact->inexactして結果を浮動小数点数に変換します。これがあなたの例です:

> (exact->inexact 
     (- #e183052866407243622723319.24395251
        #e183052866407243622723319.00))
0.24395251
于 2013-04-15T12:08:18.630 に答える