【问题标题】:Round a divided number in Bash在 Bash 中舍入除数
【发布时间】:2010-03-07 05:25:18
【问题描述】:

我如何将两个除数的结果四舍五入,例如

3/2

和我一样

testOne=$((3/2))

$testOne 包含“1”,而它应该四舍五入到“2”作为 3/2=1.5 的答案

【问题讨论】:

  • 基本上是 SO 2394988 (stackoverflow.com/questions/2394988) 的 DUP - 同一张海报。
  • 当然它非常相似,但我不会称它为 DUP,但现在可以关闭它,因为无论如何我现在已经得到了答案,谢谢 ghostdog!
  • 同意!这两个问题不一样。一是要求天花板。这个要求四舍五入,可能是向上或向下舍入。

标签: linux bash math shell rounding


【解决方案1】:

要在截断算术中进行四舍五入,只需将 (denom-1) 添加到分子即可。

示例,四舍五入:

N/2
M/5
K/16

例如,四舍五入:

(N+1)/2
(M+4)/5
(K+15)/16

要进行最近的四舍五入,请将(denom/2) 添加到分子(一半将四舍五入):

(N+1)/2
(M+2)/5
(K+8)/16

【讨论】:

  • 你能再解释一下吗?一个面额是什么意思?而且我真的不明白所有这些括号和字母在做什么......?我觉得我应该知道,因为没有其他答案和 5+ ups
  • @Mint:他正在使用代数符号显示一个广义的答案。使用您的 Bash 示例,它看起来像这样:testOne=$(( (3 + (2 - 1) / 2))。更一般地说,但在 Bash 语法中,它类似于answer=$(( ($numerator + ($denominator - 1) / $denomonator))。您也可以这样做,消除所有美元符号并允许更多的空格(例如等号周围):((answer = (numerator + (denominator - 1) / denomonator))
  • 是的,我在这些括号上打错了。
  • @tommy.carstensen:你是对的。这里没有迹象表明问题涉及负数(脚本问题通常不会)。负数可以用类似的方式处理,但公式会很快变得复杂。
  • 不正确 testOne=$(( (3 + (2 - 1) / 2)) 正确:testOne=$(( (3 + (2 - 1)) / 2))
【解决方案2】:

好的解决方案是获得最近的轮数

var=2.5
echo $var | awk '{print int($1+0.5)}'

如果 var 十进制值小于 0.5,那么逻辑很简单,那么最接近的值就是整数值。好吧,如果十进制值大于 0.5,则添加下一个整数值,并且由于 awk 然后只取整数部分。问题解决了

【讨论】:

  • 在我将内存使用量从 KB 转换为 MB 时非常有用,因为我不太关心小数部分
【解决方案3】:

bash 不会为您提供正确的 3/2 结果,因为它不进行浮动 pt 数学运算。你可以使用像awk这样的工具

$ awk  'BEGIN { rounded = sprintf("%.0f", 3/2); print rounded }'
2

或公元前

$ printf "%.0f" $(echo "scale=2;3/2" | bc)
2

【讨论】:

  • awk 'BEGIN { rounded = sprintf("%.0f", 1/2); print rounded }' 返回 0 而不是 1。
  • 您应该注意,这会进行无偏舍入。
  • 我喜欢这个,因为它更具可读性(数学变通方法很好但不可读),而且我不需要超过 0.5 舍入的精度。请注意awk 'BEGIN { rounded = sprintf("%.0f", 1.000001/2); print rounded }' 返回 1
  • 无偏舍入意味着 $ echo 4.5 |awk '{printf "%.0f",$0}' 给出 4 而$ echo 5.5 |awk '{printf "%.0f",$0}' 给出 6 – 将 0.5 舍入到最接近的 偶数 整数
【解决方案4】:

如果您对正数进行整数除法并朝零舍入,那么您可以将除数减去 1 以使其向上舍入。

也就是说,将X / Y替换为(X + Y - 1) / Y

证明:

  • 案例 1:X = k * Y(X 是 Y 的整数倍):在这种情况下,我们有 (k * Y + Y - 1) / Y,它拆分为 (k * Y) / Y + (Y - 1) / Y(Y - 1)/Y 部分舍入为零,剩下的商为 k这正是我们想要的:当输入可整除时,我们希望调整后的计算仍能产生正确的精确商。

  • 案例 2:X = k * Y + m 其中0 < m < Y(X 不是 Y 的倍数)。在这种情况下,我们有一个分子k * Y + m + Y - 1k * Y + Y + m - 1,我们可以将除法写成(k * Y)/Y + Y/Y + (m - 1)/Y。由于0 < m < Y0 <= m - 1 < Y - 1 等最后一项(m - 1)/Y 变为零。我们留下了(k * Y)/Y + Y/Y,它的结果是k + 1。这表明行为四舍五入。如果我们有一个X,它是k 的倍数Y,如果我们只给它加1,则除法四舍五入到k + 1

但是这个四舍五入是极端相反的;所有不精确的除法都远离零。介于两者之间怎么样?

这可以通过用Y/2“启动”分子来实现。计算(X+Y/2)/Y,而不是X/Y。而不是证明,让我们对此进行实证:

$ round()
> {
>   echo $((($1 + $2/2) / $2))
> }
$ round 4 10
0
$ round 5 10
1
$ round 6 10
1
$ round 9 10
1
$ round 10 10
1
$ round 14 10
1
$ round 15 10
2

只要除数是偶数,正数,如果分子与该数的一半相等,则向上舍入,如果小于该数,则向下舍入。

例如,round 6 12 转到 1,所有等于 6 的值都以 12 为模,例如 18(转到 2)等等。 round 5 12 下降到 0

对于奇数,行为是正确的。没有一个确切的有理数在两个连续倍数之间。例如,分母为11,我们有5/11 < 5.5/11 (exact middle) < 6/11;和round 5 11 向下取整,而round 6 11 向上取整。

【讨论】:

  • 这是一个很棒的解决方案,我喜欢将它捆绑为一个函数。为澄清起见,函数round x yx 除以y 并四舍五入到最接近的整数。
【解决方案5】:

给定一个浮点值,我们可以用printf 简单地舍入它:

# round $1 to $2 decimal places
round() {
    printf "%.${2:-0}f" "$1"
}

那么,

# do some math, bc style
math() {
    echo "$*" | bc -l
}

$ echo "Pi, to five decimal places, is $(round $(math "4*a(1)") 5)"
Pi, to five decimal places, is 3.14159

或者,使用原始请求:

$ echo "3/2, rounded to the nearest integer, is $(round $(math "3/2") 0)"
3/2, rounded to the nearest integer, is 2

【讨论】:

  • printf "%.0f" "0.5" 打印0 而不是预期的1,而printf "%.0f" "0.6" 打印1 如预期的那样。
  • 恕我直言printf "%.2f" "$1" 是错误的:printf "%.0f" "2.6"bash: printf: 2.6: invalid number
  • 打错字了。应该是printf "%.${2:-0}f" "$1"。我无法更改 1 个字符 :-(
【解决方案6】:

要四舍五入,您可以使用模数。

如果有余数,等式的第二部分将添加到 True。 (真 = 1;假 = 0)

例如:3/2

answer=$(((3 / 2) + (3 % 2 > 0)))
echo $answer
2

例如:100 / 2

answer=$(((100 / 2) + (100 % 2 > 0)))
echo $answer
50

例如:100 / 3

answer=$(((100 / 3) + (100 % 3 > 0)))
echo $answer
34

【讨论】:

    【解决方案7】:

    如果小数点分隔符是逗号(例如:LC_NUMERIC=fr_FR.UTF-8,请参阅here):

    $ printf "%.0f" $(echo "scale=2;3/2" | bc) 
    bash: printf: 1.50: nombre non valable
    0
    

    ghostdog74 解决方案需要替换:

    $ printf "%.0f" $(echo "scale=2;3/2" | bc | sed 's/[.]/,/')
    2
    

    $ printf "%.0f" $(echo "scale=2;3/2" | bc | tr '.' ',')
    2
    

    【讨论】:

      【解决方案8】:

      另一种解决方案是在 python 命令中进行除法。例如:

      $ numerator=90
      $ denominator=7
      $ python -c "print (round(${numerator}.0 / ${denominator}.0))"
      

      对我来说似乎没有使用 awk 过时。

      【讨论】:

      • 附录:四舍五入时也可以使用地板除法: print ${numerator} // ${denominator}
      • 为什么不从 bash 调用 Java?根据创建者的说法,Java 速度非常快,并且具有高性能的算术运算。这当然是个玩笑,但这个玩笑很可悲,因为你的例子就像 Java 在 bash 中的算术一样荒谬。
      【解决方案9】:

      我认为这应该足够了。

      $ echo "3/2" | bc 
      

      【讨论】:

      • 这适用于您的示例,但是 echo "2.5*3" | bc 给出了 7.5
      【解决方案10】:

      以下对我有用。

       #!/bin/bash
      function float() {
      bc << EOF
      num = $1;
      base = num / 1;
      if (((num - base) * 10) > 1 )
          base += 1;
      print base;
      EOF
      echo ""
      }
      
      float 3.2
      

      【讨论】:

        猜你喜欢
        • 2015-01-07
        • 1970-01-01
        • 1970-01-01
        • 2018-12-24
        • 2017-01-12
        • 1970-01-01
        • 2013-04-23
        • 2012-06-19
        • 1970-01-01
        相关资源
        最近更新 更多