在 bash 中计算平方根到小数位
Calculate Square root to decimal places in bash
我正在编写一个简单的 bash 脚本来默认计算小数点后 3 位的平方根,但用户可以设置位数...没什么复杂的,我只是从 1 迭代到最低平方根。由于我的 bash 仍然是基本的,这就是我想出的。
#!/usr/bin/env bash
num=
places=${2-3}
i=0
while [[ $(( i*i )) -lt ${num} ]] // <= The problem should be here
do
i=$(( i + 1 ))
done
echo ${i};
rem=$(( num % i ))
root="${i}."
for (( j=0; j<places; j++ ))
do
rem=$((rem * 10))
root="$root$((rem / i))"
rem=$((rem % i))
done
echo ${root}
但由于某些原因,它不会为大范围的数字生成正确的结果
喜欢bashfile.sh 9 // will produce 3.000 but bashfile.sh 8 will return 3.666
请帮忙,while [[ ]]
有什么问题
以上代码尝试通过几个步骤计算带小数的 sqrt:
- 计算N的整数部分,存为I
- 用 R 除以 I 计算 R=N-I*I 的小数部分。
但是,这是不正确的。该代码假定将 N 分成 = (II) + (DI),但是,要求是找到 N = (D+I)(D +I) = DD + II + 2(D+I)
两种可能的选择:
- 将数字乘以 10^(PREC*2),将 sqrt 取为整数,然后打印小数点后最后一位 PREC 数字的数字。
- 转义到能够处理十进制数的工具(awk、bc 或 dc)
- 将十进制计算实现为二分查找
实施选项 #1:
PREC=3 # Precision
V=123456 # input
for ((i=1 ; i<=PREC ; i++ )) ; do
V=V*100
done
# Loop for matching i as above
这是一个相当简单但效率不高的解决方案:
#!/bin/bash
num=
prec=${2:-3}
for (( i=0; i < prec; ++i )); do let num*=100; done
for (( sqrt=0; sqrt*sqrt <= num; ++sqrt )); do :; done
let --sqrt
sqrt="${sqrt:0:-prec}.${sqrt: -prec}"
echo $sqrt
为了回答您的问题 ("what is wrong with while [[ ]]
"),您的比较稍有不正确。它应该是 <=
而不是 -lt
(即 <
)。并且您需要在循环后从 i
中减去 1 以获得平方根的正确整数部分。
我无法理解您计算小数位的代码的第二部分。然而,一个简单的解决方案是预乘原始数字以获得所需的精度,这就是我在上面所做的。
更新
正如@dash-o 所指出的,如果您正在使用 bash,您可能安装了 bc 或 awk,它们更适合于此:
num=
prec=${2:-3}
# using bc
echo "scale=$prec; sqrt($num)" | bc
# using awk
awk "BEGIN {printf \"%.${prec}f\n\", sqrt($num)}"
我正在编写一个简单的 bash 脚本来默认计算小数点后 3 位的平方根,但用户可以设置位数...没什么复杂的,我只是从 1 迭代到最低平方根。由于我的 bash 仍然是基本的,这就是我想出的。
#!/usr/bin/env bash
num=
places=${2-3}
i=0
while [[ $(( i*i )) -lt ${num} ]] // <= The problem should be here
do
i=$(( i + 1 ))
done
echo ${i};
rem=$(( num % i ))
root="${i}."
for (( j=0; j<places; j++ ))
do
rem=$((rem * 10))
root="$root$((rem / i))"
rem=$((rem % i))
done
echo ${root}
但由于某些原因,它不会为大范围的数字生成正确的结果
喜欢bashfile.sh 9 // will produce 3.000 but bashfile.sh 8 will return 3.666
请帮忙,while [[ ]]
以上代码尝试通过几个步骤计算带小数的 sqrt:
- 计算N的整数部分,存为I
- 用 R 除以 I 计算 R=N-I*I 的小数部分。
但是,这是不正确的。该代码假定将 N 分成 = (II) + (DI),但是,要求是找到 N = (D+I)(D +I) = DD + II + 2(D+I)
两种可能的选择:
- 将数字乘以 10^(PREC*2),将 sqrt 取为整数,然后打印小数点后最后一位 PREC 数字的数字。
- 转义到能够处理十进制数的工具(awk、bc 或 dc)
- 将十进制计算实现为二分查找
实施选项 #1:
PREC=3 # Precision
V=123456 # input
for ((i=1 ; i<=PREC ; i++ )) ; do
V=V*100
done
# Loop for matching i as above
这是一个相当简单但效率不高的解决方案:
#!/bin/bash
num=
prec=${2:-3}
for (( i=0; i < prec; ++i )); do let num*=100; done
for (( sqrt=0; sqrt*sqrt <= num; ++sqrt )); do :; done
let --sqrt
sqrt="${sqrt:0:-prec}.${sqrt: -prec}"
echo $sqrt
为了回答您的问题 ("what is wrong with while [[ ]]
"),您的比较稍有不正确。它应该是 <=
而不是 -lt
(即 <
)。并且您需要在循环后从 i
中减去 1 以获得平方根的正确整数部分。
我无法理解您计算小数位的代码的第二部分。然而,一个简单的解决方案是预乘原始数字以获得所需的精度,这就是我在上面所做的。
更新
正如@dash-o 所指出的,如果您正在使用 bash,您可能安装了 bc 或 awk,它们更适合于此:
num=
prec=${2:-3}
# using bc
echo "scale=$prec; sqrt($num)" | bc
# using awk
awk "BEGIN {printf \"%.${prec}f\n\", sqrt($num)}"