在 Bash 中用 bc 舍入数字
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26861118/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Rounding Numbers with bc in Bash
提问by Yasin Kaya
I want to compute an average with 3 decimal figures, rounded to nearest, using bc
.
我想用 3 位小数计算平均值,四舍五入到最接近,使用bc
.
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. What can I do to solve my problem?
但scale
不符合我的预期。我能做些什么来解决我的问题?
采纳答案by gniourf_gniourf
Your trick to add 0.0005
is not a bad idea. Though, it doesn't quite work that way. scale
is used internally when bc
performs some operations (like divisions).
你添加的技巧0.0005
不是一个坏主意。尽管如此,它并不完全如此。scale
在bc
执行某些操作(如除法)时在内部使用。
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. Fortunately, bc
has some conditional operators.
当然,无论sum
是积极的还是消极的,您都希望以不同的方式进行。幸运的是,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() {
# is expression to round (should be a valid bc expression)
# is number of decimal figures (optional). Defaults to three if none given
local df=${2:-3}
printf '%.*f\n' "$df" "$(bc -l <<< "a=; 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
1with the -l
switch, scale
is set to 20
, which should be plenty enough.
1与-l
开关,scale
设置为20
,应该足够了。
回答by Serge3leo
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
}
回答by poinck
This solution is not that flexibile (it just converts float to int), but it can deal with negative numbers:
这个解决方案不是那么灵活(它只是将 float 转换为 int),但它可以处理负数:
e=$( echo "scale=0; (${e}+0.5)/1" | bc -l )
if [[ "${e}" -lt 0 ]] ; then
e=$(( e - 1 ))
fi