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

당신이 이해해야 할 것표현의 규모존재하다 bc. bc할수있다임의의 정밀도(이것이 반드시 무한한 정확성을 의미하는 것은 아닙니다.) 그리고계산자프로세서의 정밀도 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

,숫자 십진 문자( 또는 )를 사용하는 데 문제가 있는 경우 .다음 버전을 사용할 수 있습니다.

$ 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

그러나 전반적으로 이것은 나쁜 생각입니다.

관련 정보