在 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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 11:46:09  来源:igfitidea点击:

Rounding Numbers with bc in Bash

linuxbashbc

提问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 scaledoesn't behave as I expect. What can I do to solve my problem?

scale不符合我的预期。我能做些什么来解决我的问题?

采纳答案by gniourf_gniourf

Your trick to add 0.0005is not a bad idea. Though, it doesn't quite work that way. scaleis used internally when bcperforms some operations (like divisions).

你添加的技巧0.0005不是一个坏主意。尽管如此,它并不完全如此。scalebc执行某些操作(如除法)时在内部使用。

In your case, it would be better to perform the division first, maybe using a large scaleor the -lswitch to bc1(if your version supports it), then add 0.0005and then set scale=3and perform an operation involving scaleinternally to have the truncation performed.

在您的情况下,最好先执行除法,可能使用大scale-l切换到bc1(如果您的版本支持),然后添加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 sumis positive or negative. Fortunately, bchas 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 -lswitch, scaleis 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