【问题标题】:Rounding to nearest power of two in bash在bash中四舍五入到最接近的二的幂
【发布时间】:2023-03-28 16:30:01
【问题描述】:

我正在编写 shell 脚本,我想将给定的整数四舍五入到最接近的 2 次方。我们可以使用 linux 命令行中可用的任何标准工具。你可以假设 bash。所以算术扩展和 bc 都可以使用。

在对数刻度上四舍五入到最接近的 2 次方(不是作为 shell 脚本):

r = 2^(round(log2(x)));

想象一个函数的输入和输出如下:

# power2 11
8
# power2 12
16
# power2 13
16
# power2 16
16

我不确定我们是否可以从 bash shell 脚本中获得日志。我们有圆吗?不确定。

但我知道你非常聪明,可以提出一个优雅而令人印象深刻的解决方案。

【问题讨论】:

  • 请在您的问题中添加示例输入和该示例输入所需的输出。
  • Bash 不支持非整数算术,更不用说超越函数了,所以你不能使用对数。您可以转换为二进制,使用最重要的 1 之后的位来决定是向上还是向下舍入,然后将其余位变为 0..

标签: bash shell math scripting arithmetic-expressions


【解决方案1】:

使用此功能:

power2() { echo "x=l($1)/l(2); scale=0; 2^((x+0.5)/1)" | bc -l; }

示例

$ power2 11
8
$ power2 12
16
$ power2 13
16
$ power2 16
16
$ power2 63
64

工作原理

echo 语句创建一个字符串,bc 将解释为命令。命令包括以下内容:

  • x=l($1)/l(2)

    这会将x 设置为第一个参数l($1) 的自然对数除以2 的自然对数l(2)

  • scale=0

    通过将scale 设置为 0,未来的除法将截断为整数。

  • 2^((x+0.5)/1)

    表达式(x+0.5)/1x 舍入为最接近的整数。然后我们将其结果乘以 2。

【讨论】:

  • scale=0 只是做地板还是四舍五入?
  • @WesModes 我的第一个版本没有四舍五入。当前的(请参阅更新的答案)可以。
  • 做得很好。纠正舍入问题的好工作。并以 1 到 3 行的形式获得它的荣誉。
  • @WesModes 我刚刚为答案添加了解释。是的,scale=0 会导致未来的分区落地,而不是圆形。正如您可能观察到的那样,我通过在需要的地方添加 0.5 来纠正这个问题。
【解决方案2】:

这个怎么样?这种方法依赖于位移,直到你到达最后一位,它位于原始数字最接近的位置的位置(或 1-off)。不需要 bc 知识,只需简单的换档。所以按位计算,1001000 将最接近 1000000 或 10000000,您只需找到最接近的。

#!/bin/sh
ORIG=$1
A=$1
C=1
while [ $A -ne 1 ]; do
  A=$((A>>1))
  C=$((C<<1))
done
NEXT=$((C<<1))
DIFF1=$((ORIG-C))
DIFF2=$((NEXT-ORIG))
if [  "$DIFF1" -ge "$DIFF2" ]; then
  echo "$NEXT"
else
  echo "$C"
fi

【讨论】:

    【解决方案3】:

    您需要使用bc。要计算 17 的以 2 为底的对数,

    X=17

    logresult=$( echo "l($x)/l(2)" | bc -l )

    [answer=4.08746284125]

    四舍五入,

    roundresult=$( echo "($logresult+0.5)/1" | bc )

    [answer=4]

    求幂,

    echo "2^$roundresult" | bc -l

    [answer=16]

    将它们放入 bash 脚本中,

    #!/bin/bash x=$1 logresult=$( echo "l($x)/l(2)" | bc -l ) roundresult=$( echo "($logresult+0.5)/1" | bc ) echo "2^$roundresult" | bc -l

    运行这个,

    ./script.sh 17

    16

    【讨论】:

      【解决方案4】:

      只是添加另一种可能性:

      power2() {
          local x=${1#-} n=1
          while ((n<x)); do ((n*=2)); done
          x=$((3*n>4*x?n/2:n))
          echo $(($1<0?-x:x))
      }
      

      也适用于 0 和负数。如果第一个参数未设置或不是数字或超出整数限制的数字(可能存在无限循环),则未指定结果。如果您使用它,请确保您真正控制输入。除此之外,它是纯 Bash。这个想法是找到 2 的幂(比如 n),使得输入(比如 x)满足 n/2 x≤n,然后找出 nn/2 中哪个最接近 x。

      【讨论】:

        猜你喜欢
        • 2011-05-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-04-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多