BCの浮動小数点演算は不正確ですか?

BCの浮動小数点演算は不正確ですか?

bc を使用してシェルで浮動小数点演算を実行する場合、通常の計算機を使用すると結果が異なります。私は何が間違っていましたか?

たとえば、球の体積を求める必要があります。ユーザーは半径の値を入力します。

pi = 3.14

volume=$(echo "scale = 2; (4 / 3) * $pi * ($r ^ 3)" | bc)
echo "Volume is $volume"

半径 = 3 の場合、unix は 112.59 を返し、計算機は 113.1 を返します。

答え1

あなたが理解すべきこと表現の規模存在するbcbcできる任意の精度(これが必ずしも無限の精度を意味するわけではありません。)計算者プロセッサの精度やfloatデータ型がある可能性があります。double

存在するbc。これスケール点の後の小数点以下の桁数なので精度に関係があります。これスケール式の値は、scale関連する演算子と変数に依存する規則によって決まります(変数は式を提供する変数です)。普段着寸法正確つまりbc、好きなだけ正確に作成できます。

たとえば、除算結果の小数点以下の桁数はですscale。だからが2の4/3とき、そうです。非常におおよその近似です。の規模は(の規模との規模はどこにありますか?)ので、ここではです。そうなるでしょう。scale1.334/3x * ymin(a+b,max(scale,a,b))axby21.33 * 3.144.17

ルールを確認するにはPOSIX仕様bc

より高い精度が必要な場合は増やしてくださいscale。無限に増やすことができます。を使用するとbc -l自動的scaleに設定されます20

$ pi='(a(1)*4)' r=3
$ $ echo "(4 / 3) * $pi * ($r ^ 3)" | bc -l
113.09733552923255658339

$ echo "scale=1000; (4 / 3) * $pi * ($r ^ 3)" | bc -l
113.0973355292325565846551617980621038310980983775038095550980053230\
81390626303523950609253712316214447357331114478163039295378405943820\
96034211293869262532022821022769726978675980014720642616237749375071\
94371951239736040606251233364163241939497632687292433484092445725499\
76355759335682169861368969085854085132237827361174295734753154661853\
14730175311724413325296040789909975753679476982929026989441793959006\
17331673453103113187002257495740245517842677306806456786589844246678\
87098096084205774588430168674012241047863639151096770218070228090538\
86527847499397329973941181834655436308584829346483609858475202045257\
72294881898002877683392804259302509384339728638724440983234852757850\
73357828522068813321247512718420036644790591105239053753290671891767\
15857867345960859999994142720979823815034238137946746942088054039248\
86988951308030971204086612694295227741563601129621951039171511955017\
31142218396089302929537125655435196874321744263099764736353375070480\
1468800991581641650380680694035580030527317911271523

$ echo "scale=1; (4 / 3) * $pi * ($r ^ 3)" | bc -l
97.2

また、すべての計算にhighを使用し、scale最終的に表示のためにこれを減らすこともできます。

$ echo "scale=10; (4 / 3) * $pi * ($r ^ 3)" | bc -l
113.0973355107
$ echo "scale=100; x = (4 / 3) * $pi * ($r ^ 3); scale = 10; x / 1" | bc -l
113.0973355292

答え2

より良い値を使用し、スケールをデフォルト値(20桁)piとして定義できるようにする必要があります。bc

$ echo "r=3; pi=4*a(1); (4/3)*pi*(r^3)" | bc -l
113.09733552923255658339

これは計算を実行するより良い方法です。倍率は、結果の数値出力形式を指定するパラメータではなく、計算に使用される精度を定義するパラメータです。

数値書式を指定するには、printf を使用できます。

$ result="$(echo "r=3; pi=4*a(1); (4/3)*pi*(r^3)" | bc -l)"
$ printf '%.2f' "$result"
113.10

,数字の 10 進文字 ( または ) の使用に問題がある場合は、次の.バージョンを使用できます。

$ LC_NUMERIC=C printf '%.2f' "$result"
113.10

printf は IEEE 754 に従って数値丸めを実装します。

もちろん、最後に小数点以下の桁数を変更して、bcが小数点以下の桁数を切り捨てることができます。

$ echo "r=3; pi=4*a(1); res=(4/3)*pi*(r^3); scale=2; res/1" | bc -l
113.09

しかし、全体的にこれは悪い考えです。

関連情報