在 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 然后找出 n 或 n/2 中的哪个是最接近 x.
我正在 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 然后找出 n 或 n/2 中的哪个是最接近 x.