在 bash 中舍入到最接近的 2 的幂

Rounding to nearest power of two in bash

我正在 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 脚本中获取日志。我们有圆吗?不确定。

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

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

#!/bin/sh
ORIG=
A=
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

使用这个函数:

power2() { echo "x=l()/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()/l(2)

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

  • scale=0

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

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

    表达式 (x+0.5)/1 四舍五入 x 到最接近的整数。然后我们将结果提高到 2 次方。

您需要使用 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= logresult=$( echo "l($x)/l(2)" | bc -l ) roundresult=$( echo "($logresult+0.5)/1" | bc ) echo "2^$roundresult" | bc -l

运行这个,

./script.sh 17

16

只是添加另一种可能性:

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

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