【问题标题】:Rounding Numbers with bc in Bash在 Bash 中使用 bc 舍入数字
【发布时间】:2015-01-07 18:41:50
【问题描述】:

我想使用 bc 计算 3 位小数的平均值,四舍五入。

例如:

3、3 和 5 的平均值应为 3.667

3、3 和 4 的平均值应为 3.333

我试过了:

echo "scale=3; $sum/$n+0.0005" | bc

但是scale 的行为不像我预期的那样。我可以做些什么来解决我的问题?

【问题讨论】:

  • 您正在添加0.0005,因此bc 很乐意回答小数点后4 位。
  • 那我该怎么办?
  • 所以你有一个XYproblem
  • 希望您阅读我在之前评论中添加的链接。您绝对应该编辑您的问题并指定: 1. 清楚地说明您想要达到的目标:我想用 3 位小数计算平均值,四舍五入到最接近的值。 2. 说明您尝试了什么,并说明为什么它不起作用。
  • 这里有很多问题的答案:askubuntu.com/questions/179898/…

标签: linux bash bc


【解决方案1】:

您添加0.0005 的技巧不是一个坏主意。虽然,它并不完全那样工作。 scalebc 执行某些操作(如除法)时在内部使用。

在您的情况下,最好先执行除法,也许使用大的scale-l 切换到bc1(如果您的版本支持),然后添加0.0005 然后设置scale=3 并在内部执行涉及scale 的操作以执行截断。

类似:

`a=$sum/$n+0.0005; scale=3; a/1`

当然,无论sum 是肯定的还是否定的,您都希望以不同的方式进行。幸运的是,bc 有一些条件运算符。

`a=$sum/$n; if(a>0) a+=0.0005 else if (a<0) a-=0.0005; scale=3; a/1`

然后,您需要使用printf 格式化此答案。

包装在函数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")"
}

试试看:

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 使用-l 开关,将scale 设置为20,应该足够了。

【讨论】:

  • 谢谢!有用。但似乎我必须做很多工作才能编写这样的代码
  • 我在 C++ 上工作过,这很容易,因为语法并不重要
  • 据我所知,语法(空格 .. 等)在 Bash 中非常重要
  • 是的,Bash 的语法非常疯狂。祝你好运!
【解决方案2】:

下一个函数将参数“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
} 

【讨论】:

    【解决方案3】:

    这个解决方案不是那么灵活(它只是将 float 转换为 int),但它可以处理负数:

    e=$( echo "scale=0; (${e}+0.5)/1" | bc -l )
    if [[ "${e}" -lt 0 ]] ; then
        e=$(( e - 1 ))
    fi
    

    【讨论】:

      猜你喜欢
      • 2015-07-18
      • 1970-01-01
      • 1970-01-01
      • 2016-03-31
      • 1970-01-01
      • 2013-02-15
      • 1970-01-01
      • 1970-01-01
      • 2016-09-21
      相关资源
      最近更新 更多