[英]Rounding Numbers with bc in Bash
I want to compute an average with 3 decimal figures, rounded to nearest, using bc
. 我想用
bc
计算一个带有3位小数的平均值,四舍五入到最接近的数字。
For example: 例如:
average of 3, 3 and 5 should yield 3.667
平均值为3,3和5应该产生3.667
and 和
average of 3, 3 and 4 should yield 3.333
平均值为3,3和4应该产生3.333
I tried: 我试过了:
echo "scale=3; $sum/$n+0.0005" | bc
but scale
doesn't behave as I expect. 但
scale
并不像我预期的那样。 What can I do to solve my problem? 我该怎么做才能解决我的问题?
Your trick to add 0.0005
is not a bad idea. 你添加
0.0005
技巧并不是一个坏主意。 Though, it doesn't quite work that way. 虽然,它并不是那么有效。
scale
is used internally when bc
performs some operations (like divisions). 当
bc
执行某些操作(如分区)时,内部使用scale
。
In your case, it would be better to perform the division first, maybe using a large scale
or the -l
switch to bc
1 (if your version supports it), then add 0.0005
and then set scale=3
and perform an operation involving scale
internally to have the truncation performed. 在你的情况下,最好先执行除法,可能使用
scale
或-l
开关到bc
1 (如果你的版本支持它),然后加0.0005
然后设置scale=3
并执行涉及scale
的操作在内部进行截断。
Something like: 就像是:
`a=$sum/$n+0.0005; scale=3; a/1`
Of course, you'll want to proceed differently whether sum
is positive or negative. 当然,无论
sum
是正数还是负数,您都希望以不同方式进行。 Fortunately, bc
has some conditional operators. 幸运的是,
bc
有一些条件运算符。
`a=$sum/$n; if(a>0) a+=0.0005 else if (a<0) a-=0.0005; scale=3; a/1`
You'll then want to format this answer using printf
. 然后,您将要使用
printf
格式化此答案。
Wrapped in a function round
(where you can optionally select the number of decimal figures): 包含在函数
round
(您可以选择小数位数):
round() {
# $1 is expression to round (should be a valid bc expression)
# $2 is number of decimal figures (optional). Defaults to three if none given
local df=${2:-3}
printf '%.*f\n' "$df" "$(bc -l <<< "a=$1; if(a>0) a+=5/10^($df+1) else if (a<0) a-=5/10^($df+1); scale=$df; a/1")"
}
Try it: 试试吧:
gniourf$ round "(3+3+4)/3"
3.333
gniourf$ round "(3+3+5)/3"
3.667
gniourf$ round "-(3+3+5)/3"
-3.667
gniourf$ round 0
0.000
gniourf$ round 1/3 10
0.3333333333
gniourf$ round 0.0005
0.001
gniourf$ round 0.00049
0.000
1 with the -l
switch, scale
is set to 20
, which should be plenty enough. 1使用
-l
开关, scale
设置为20
,这应该足够了。
Next function round argument 'x' to 'd' digits: 下一个函数将参数'x'转换为'd'数字:
define r(x, d) {
auto r, s
if(0 > x) {
return -r(-x, d)
}
r = x + 0.5*10^-d
s = scale
scale = d
r = r*10/10
scale = s
return r
}
This solution is not that flexibile (it just converts float to int), but it can deal with negative numbers: 这个解决方案不是flexibile(它只是将float转换为int),但它可以处理负数:
e=$( echo "scale=0; (${e}+0.5)/1" | bc -l )
if [[ "${e}" -lt 0 ]] ; then
e=$(( e - 1 ))
fi
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.