如何在bash中使用浮点除法?

时间:2012-10-04 07:16:56

标签: bash floating-point arithmetic-expressions

我试图在Bash脚本中划分两个图像宽度,但是bash会给我0作为结果:

RESULT=$(($IMG_WIDTH/$IMG2_WIDTH))

我确实研究了Bash指南,我知道我应该使用bc,在互联网的所有示例中,他们使用bc。在echo中,我尝试在我的SCALE中添加相同的内容,但它不起作用。

以下是我在教程中找到的示例:

echo "scale=2; ${userinput}" | bc 

我怎样才能让Bash给我一个像0.5那样的浮动?

19 个答案:

答案 0 :(得分:204)

你做不到。 bash 只有做整数;您必须委托给bc等工具。

答案 1 :(得分:160)

你可以这样做:

bc <<< 'scale=2; 100/3'
33.33

更新 20130926:您可以使用:

bc -l <<< '100/3' # saves a few hits

答案 2 :(得分:108)

的bash

正如其他人所指出的那样,bash不支持浮点运算,尽管你可以用一些固定的十进制技巧伪造它,例如有两位小数:

echo $(( 100 * 1 / 3 )) | sed 's/..$/.&/'

输出:

.33

有关类似但更简洁的方法,请参阅Nilfred's answer

替代

除了提及的bcawk替代方案之外,还有以下内容:

CLISP

clisp -x '(/ 1.0 3)'

清理输出:

clisp --quiet -x '(/ 1.0 3)'

或通过stdin:

echo '(/ 1.0 3)' | clisp --quiet | tail -n1

直流

echo 2k 1 3 /p | dc

天才cli计算器

echo 1/3.0 | genius

gnuplot的

echo 'pr 1/3.' | gnuplot

JQ

echo 1/3 | jq -nf /dev/stdin

或者:

jq -n 1/3

ksh的

echo 'print $(( 1/3. ))' | ksh

LUA

lua -e 'print(1/3)'

或通过stdin:

echo 'print(1/3)' | lua

最大值

echo '1/3,numer;' | maxima

清理输出:

echo '1/3,numer;' | maxima --quiet | sed -En '2s/[^ ]+ [^ ]+ +//p'

节点

echo 1/3 | node -p

八度

echo 1/3 | octave

perl的

echo print 1/3 | perl

echo print 1/3. | python

- [R

echo 1/3 | R --no-save

清理输出:

echo 1/3 | R --vanilla --quiet | sed -n '2s/.* //p'

红宝石

echo print 1/3.0 | ruby

wcalc

echo 1/3 | wcalc

清理输出:

echo 1/3 | wcalc | tr -d ' ' | cut -d= -f2

的zsh

echo 'print $(( 1/3. ))' | zsh

单元

units 1/3

紧凑的输出:

units --co 1/3

其他来源

在Unix.SX上

Stéphane Chazelas answered a similar question结束。

答案 3 :(得分:35)

稍微改善马文的答案:

RESULT=$(awk "BEGIN {printf \"%.2f\",${IMG_WIDTH}/${IMG2_WIDTH}}")

bc并不总是作为已安装的软件包。

答案 4 :(得分:26)

您可以使用-l选项(L字母)

来使用bc
RESULT=$(echo "$IMG_WIDTH/$IMG2_WIDTH" | bc -l)

答案 5 :(得分:24)

作为bc的替代方案,您可以在脚本中使用awk。

例如:

echo "$IMG_WIDTH $IMG2_WIDTH" | awk '{printf "%.2f \n", $1/$2}'

在上面,“%。2f”告诉printf函数返回小数位后两位数的浮点数。由于awk在它们上正常运行,我使用echo将变量作为字段输入管道。 “$ 1”和“$ 2”指的是输入awk的第一个和第二个字段。

您可以使用以下内容将结果存储为其他变量:

RESULT = `echo ...`

答案 6 :(得分:17)

现在是尝试zsh(一个(差不多)bash超集)的最佳时机,还有许多其他不错的功能,包括浮点数学。以下是您在zsh中的示例:

% IMG_WIDTH=1080
% IMG2_WIDTH=640
% result=$((IMG_WIDTH*1.0/IMG2_WIDTH))
% echo $result
1.6875

这篇文章可以帮助您:bash - Worth switching to zsh for casual use?

答案 7 :(得分:13)

好吧,浮动之前是使用固定小数逻辑的时间:

IMG_WIDTH=100
IMG2_WIDTH=3
RESULT=$((${IMG_WIDTH}00/$IMG2_WIDTH))
echo "${RESULT:0:-2}.${RESULT: -2}"
33.33

最后一行是bashim,如果不使用bash,请尝试使用此代码:

IMG_WIDTH=100
IMG2_WIDTH=3
INTEGER=$(($IMG_WIDTH/$IMG2_WIDTH))
DECIMAL=$(tail -c 3 <<< $((${IMG_WIDTH}00/$IMG2_WIDTH)))
RESULT=$INTEGER.$DECIMAL
echo $RESULT
33.33

代码背后的基本原理是:在除以得到2位小数之前乘以100。

答案 8 :(得分:4)

有些场景你不能使用bc因为它可能根本就不存在,比如在busybox或嵌入式系统的某些减少版本中。在任何情况下,限制外部依赖性始终是一件好事,所以你总是可以将零加到除以(分子)的数字,这与乘以10的幂相同(你应该选择10的幂)你需要的精度),这将使除法输出一个整数。一旦你有了这个整数就把它当作一个字符串并将小数点(从右向左移动)的次数等于10乘以分子的幂。这是通过仅使用整数来获得浮点结果的简单方法。

答案 9 :(得分:4)

这不是真正的浮点数,但是如果你想要在bc的一次调用中设置多个结果......

source /dev/stdin <<<$(bc <<< '
d='$1'*3.1415926535897932384626433832795*2
print "d=",d,"\n"
a='$1'*'$1'*3.1415926535897932384626433832795
print "a=",a,"\n"
')

echo bc radius:$1 area:$a diameter:$d

计算半径为$ 1

的圆的面积和直径

答案 10 :(得分:3)

如果找到了首选项的变体,也可以将其包装到函数中。

在这里,我将一些bashism包装到div函数中:

一个班轮:

function div { local _d=${3:-2}; local _n=0000000000; _n=${_n:0:$_d}; local _r=$(($1$_n/$2)); _r=${_r:0:-$_d}.${_r: -$_d}; echo $_r;}

或多行:

function div {
  local _d=${3:-2}
  local _n=0000000000
  _n=${_n:0:$_d}
  local _r=$(($1$_n/$2))
  _r=${_r:0:-$_d}.${_r: -$_d}
  echo $_r
}

现在您可以使用功能

div <dividend> <divisor> [<precision=2>]

并像使用它

> div 1 2
.50

> div 273 123 5
2.21951

> x=$(div 22 7)
> echo $x
3.14

答案 11 :(得分:3)

对于那些试图用可接受的答案来计算百分比但又失去精度的人:

如果运行此命令:

echo "scale=2; (100/180) * 180" | bc

您只会得到99.00,这会降低精度。

如果以这种方式运行它:

echo "result = (100/180) * 180; scale=2; result / 1" | bc -l

现在您得到99.99

因为仅在打印时才进行缩放。

请参阅here

答案 12 :(得分:2)

如何在bash中进行浮点计算:

here strings之一一样,它没有与<<<命令一起使用“ most-upvoted examples”(bc),这是我最喜欢的bc浮点数例如,直接从EXAMPLES手册页的bc部分开始(有关手册页,请参见man bc)。

在开始之前,请知道pi的公式是:pi = 4*atan(1)。下面的a()bc的{​​{1}}数学函数。

  1. 这是将浮点计算结果存储到bash变量中的方法-在这种情况下,将其存储到名为atan() 的变量中。请注意,在这种情况下,pi将精度的小数位数设置为10。此位置后的所有十进制数字都将被截断

    scale=10
  2. 现在,要使一行代码也打印出该变量的值,只需将pi=$(echo "scale=10; 4*a(1)" | bc -l) 命令作为后续命令添加到末尾,如下所示。请注意,按命令将截断保留在小数点后10位:

    echo
  3. 最后,让我们进行一些舍入。在这里,我们将使用pi=$(echo "scale=10; 4*a(1)" | bc -l); echo $pi 3.1415926532 函数将其舍入到小数点后4位。请注意,printf现在四舍五入为3.14159...。由于四舍五入,我们不再需要使用3.1416截断到小数点后10位,因此我们只删除该部分。这是最终的解决方案:

    scale=10

这是上述技术的另一个非常出色的应用程序和演示:测量和打印运行时。

请注意,pi=$(printf %.4f $(echo "4*a(1)" | bc -l)); echo $pi 3.1416 dt_min舍入到0.01666666666...

0.017

相关:

答案 13 :(得分:1)

虽然你不能在Bash中使用浮点除法,但你可以使用定点除法。您需要做的就是将整数乘以10的幂,然后除以整数部分并使用模运算来得到小数部分。根据需要进行舍入。

#!/bin/bash

n=$1
d=$2

# because of rounding this should be 10^{i+1}
# where i is the number of decimal digits wanted
i=4
P=$((10**(i+1)))
Pn=$(($P / 10))
# here we 'fix' the decimal place, divide and round tward zero
t=$(($n * $P / $d + ($n < 0 ? -5 : 5)))
# then we print the number by dividing off the interger part and
# using the modulo operator (after removing the rounding digit) to get the factional part.
printf "%d.%0${i}d\n" $(($t / $P)) $(((t < 0 ? -t : t) / 10 % $Pn))

答案 14 :(得分:1)

使用计算。这是我发现的最简单的 例如:

  

计算1 + 1

 2
  

计算1/10

 0.1

答案 15 :(得分:1)

我知道它很旧,但是很诱人。因此,答案是:您不能...但是您可以。让我们尝试一下:

$IMG_WIDTH=1024
$IMG2_WIDTH=2048

$RATIO="$(( IMG_WIDTH / $IMG2_WIDTH )).$(( (IMG_WIDTH * 100 / IMG2_WIDTH) % 100 ))

就像您在该点之后得到2位数字一样,以纯bash形式将其截断(称为四舍五入到较低的位置,哈哈)(无需启动其他进程)。当然,如果您只需要在该点之后加一位,则可以乘以10并求模10。

这是做什么的

  • 第一个$((...))做整数除法;
  • second $((...))对大于100倍的东西进行整数除法,实际上是将您的2位数字移到该点的左边,然后(%)通过取模来只获得这2位数字。

奖金跟踪:bc版本x 1000在我的笔记本电脑上花费了1.8秒,而纯bash花费了0,016秒。

答案 16 :(得分:1)

** bash / shell中的注入安全浮点数学**

注意:此答案的重点是为在bash(或其他shell)中执行数学运算的注入安全解决方案提供想法。当然,可以使用相同的方法,只需稍作调整即可执行高级操作。字符串处理等

提出的大多数解决方案都是使用外部数据(变量,文件,命令行,环境变量)动态地构建小型scriptlet。外部输入可用于将恶意代码注入引擎,其中很多

下面是使用各种语言进行基本数学计算的比较,结果以浮点数表示。计算出A + B * 0.1(作为浮点数)。

所有解决方案都尝试避免创建很难维护的动态脚本,而是使用静态程序,并将参数传递到指定的变量中。他们将安全地处理带有特殊字符的参数-减少代码注入的可能性。 BC是例外,它不提供输入/输出功能

例外是'bc',它不提供任何输入/输出,所有数据均通过stdin中的程序提供,所有输出均提供给stdout。所有计算都在沙箱中执行,这不会产生副作用(打开文件等)。从理论上讲,注射是设计安全的!

A=5.2
B=4.3

# Awk: Map variable into awk
# Exit 0 (or just exit) for success, non-zero for error.
#
awk -v A="$A" -v B="$B" 'BEGIN { print A + B * 0.1 ; exit 0}'

# Perl
perl -e '($A,$B) = @ARGV ; print $A + $B * 0.1' "$A" "$B"

# Python
python -c 'import sys ; a = float(sys.argv[1]) ; b = float(sys.argv[2]) ; print a+b*01' "$A" "$B"

# BC
bc <<< "scale=1 ; $A + $B * 0.1"

答案 17 :(得分:0)

这是awk命令:-F =字段分隔符== +

echo "2.1+3.1" |  awk -F "+" '{print ($1+$2)}'

答案 18 :(得分:0)

正如其他人指出的那样,bash没有内置的浮点运算符。

即使不使用 bc awk 之类的计算器程序或任何与此相关的外部程序,也可以使用bash 实现浮点数

我将在我的项目shellmath中按照以下三个基本步骤进行操作:

  1. 将数字分解为整数和小数部分
  2. 使用内置的整数运算符分别处理零件,同时注意位置值和进位
  3. 重新组合结果

作为预告片,我添加了一个演示脚本,该脚本使用以x = 0为中心的泰勒级数来计算 e

如果有时间请检查一下。我欢迎您的反馈!