如何在bash中使用bc舍入小数?

使用bash脚本编写我想要的快速示例:

#!/bin/bash echo "Insert the price you want to calculate:" read float echo "This is the price without taxes:" echo "scale=2; $float/1.18" |bc -l read -p "Press any key to continue..." bash scriptname.sh 

假设价格是:48.86答案是:41.406779661(41.40实际上因为我使用scale=2;

我的问题是:我如何围绕第二个小数点以这种方式显示答案?:41.41

bash圆函数:

 round() { echo $(printf %.$2f $(echo "scale=$2;(((10^$2)*$1)+0.5)/(10^$2)" | bc)) }; 

在您的代码示例中使用:

 #!/bin/bash # the function "round()" was taken from # http://stempell.com/2009/08/rechnen-in-bash/ # the round function: round() { echo $(printf %.$2f $(echo "scale=$2;(((10^$2)*$1)+0.5)/(10^$2)" | bc)) }; echo "Insert the price you want to calculate:" read float echo "This is the price without taxes:" #echo "scale=2; $float/1.18" |bc -l echo $(round $float/1.18 2); read -p "Press any key to continue..." 

祝你好运:o)

最简单的解决方案

 printf %.2f $(echo "$float/1.18" | bc -l) 

Bash / awk舍入:

 echo "23.49" | awk '{printf("%d\n",$1 + 0.5)}' 

如果你有python你可以使用这样的东西:

 echo "4.678923" | python -c "print round(float(raw_input()))" 

这是一个纯粹的bc解决方案。 舍入规则:+/- 0.5,远离零。

将您要查找的比例放在$ result_scale中; 你的数学应该是$ MATH在bc命令列表中的位置:

 bc < 0) h=0.5 a=(m * t + h) scale=$result_scale a / t MATH 

我知道这是一个老问题,但我有一个纯’bc’解决方案没有’if’或分支:

 #!/bin/sh bcr() { echo "scale=$2+1;t=$1;scale-=1;(t*10^scale+((t>0)-(t<0))/2)/10^scale" | bc -l } 

使用它像bcr '0.666666' 2bcr '0.666666' 2 - >(表达式后跟刻度)

这是可能的,因为在bc(如C / C ++)中,允许在计算中混合逻辑表达式。 表达式((t>0)-(t<0))/2)将根据't'的符号计算为+/- 0.5,因此使用正确的值进行舍入。

 #!/bin/bash # - loosely based on the function "round()", taken from # http://stempell.com/2009/08/rechnen-in-bash/ # - inspired by user85321 @ askubuntu.com (original author) # and Aquarius Power # the round function (alternate approach): round2() { v=$1 vorig=$v # if negative, negate value ... (( $(bc <<<"$v < 0") == 1 )) && v=$(bc <<<"$v * -1") r=$(bc <<<"scale=$3;(((10^$3)*$v/$2)+0.5)/(10^$3)") # ... however, since value was only negated to get correct rounding, we # have to add the minus sign again for the resulting value ... (( $(bc <<< "$vorig < 0") == 1 )) && r=$(bc <<< "$r * -1") env printf %.$3f $r }; echo "Insert the price you want to calculate:" read float echo "This is the price without taxes:" round2 $float 1.18 2 echo && read -p "Press any key to continue..." 

它实际上很简单:没有必要为负数显式添加硬编码的“-0.5”变体。 用数学方法说,我们只计算参数的绝对值 ,并且仍然像往常一样 0.5。 但是因为我们(不幸的是)我们没有内置的abs()函数(除非我们编码一个),否则我们将简单地否定论证,如果它是负面的。

此外,使用作为参数来certificate非常麻烦(因为对于我的解决方案,我必须能够单独访问被除数和除数)。 这就是为什么我的脚本有一个额外的第三个参数。

我仍在寻找一个纯粹的bc答案,如何在函数中舍入一个值,但这里是一个纯粹的bash答案:

 #!/bin/bash echo "Insert the price you want to calculate:" read float echo "This is the price without taxes:" embiggen() { local int precision fraction="" if [ "$1" != "${1#*.}" ]; then # there is a decimal point fraction="${1#*.}" # just the digits after the dot fi int="${1%.*}" # the float as a truncated integer precision="${#fraction}" # the number of fractional digits echo $(( 10**10 * $int$fraction / 10**$precision )) } # round down if negative if [ "$float" != "${float#-}" ] then round="-5000000000" else round="5000000000" fi # calculate rounded answer (sans decimal point) answer=$(( ( `embiggen $float` * 100 + $round ) / `embiggen 1.18` )) int=${answer%??} # the answer as a truncated integer echo $int.${answer#$int} # reassemble with correct precision read -p "Press any key to continue..." 

基本上,这会小心地提取小数,将所有内容乘以1000亿(10 15,10 10**10 bash ),调整精度和舍入,执行实际除法,分回适当的大小,然后重新插入小数。

一步步:

embiggen()函数将其参数的截断整数forms分配给$int ,并将点数保存在$fraction 。 小数位数以$precision 。 数学乘以$int$fraction的串联乘以embiggen 48.86 ,然后调整以匹配精度(例如, embiggen 48.86变为10 15×4886/100并返回488600000000 ,即488,600,000,000)。

我们想要最终精度为百分之一,所以我们将第一个数乘以100,为舍入目的加5,然后除第二个数。 这个$answer分配给我们留下了最终答案的一百倍。

现在我们需要添加小数点。 我们为$answer分配一个新的$int值,不包括它的最后两位数,然后用点echo它,并且$answer除了已经处理过的$int值。 (别担心语法突出显示错误,使其看起来像评论)

(Bashism:指数不是POSIX,所以这是一个基础。纯POSIX解决方案需要循环来添加零而不是使用10的幂。此外,“embiggen”是一个完美的cromulant词。)


我使用zsh作为我的shell的主要原因之一是它支持浮点数学。 这个问题的解决方案在zsh非常简单:

 printf %.2f $((float/1.18)) 

(我很乐意看到有人在这个答案中添加注释,并在bash启用浮点运算,但我很确定这个function还不存在。)

如果你有结果,例如考虑2.3747888

你所要做的就是:

 d=$(echo "(2.3747888+0.5)/1" | bc); echo $d 

这个数字正确的例子:

 (2.49999 + 0.5)/1 = 2.99999 

小数被bc删除,因此它应该向下bc为2

我必须计算一组音频文件的总持续时间。

所以我不得不:

A.获取每个文件的持续时间( 未显示

B.将所有持续时间加起来(它们各自为NNN.NNNNNN (fp)秒)

C.分开小时,分钟,秒,亚秒。

D.输出一串HR:MIN:SEC:FRAMES,其中frame = 1/75秒。

(帧来自工作室使用的SMPTE代码。)


答:使用ffprobe和解析持续时间行到fp号码(未显示)

B:

  # add them up as a series of strings separated by "+" and send it to bc arr=( "${total[@]}" ) # copy array # IFS is "Internal Field Separator" # the * in arr[*] means "all of arr separated by IFS" # must have been made for this IFS='+' sum=$(echo "scale=3; ${arr[*]} "| bc -l)# (-l= libmath for fp) echo $sum 

C:

 # subtract each amount of time from tt and store it tt=$sum # tt is a running var (fp) hrs=$(echo "$tt / 3600" | bc) tt=$(echo "$tt - ( $hrs * 3600 )" | bc ) min=$(echo "$tt / 60" | bc ) tt=$(echo "$tt - ($min *60)" | bc ) sec=$(echo "$tt/1" | bc ) tt=$(echo "$tt - $sec" | bc ) frames=$(echo "$tt * 75" | bc ) # 75 frames /sec frames=$(echo "$frames/1" | bc ) # truncate to whole # 

d:

 #convert to proper format with printf (bash builtin) hrs=$(printf "%02d\n" $hrs) # format 1 -> 01 min=$(printf "%02d\n" $min) sec=$(printf "%02d\n" $sec) frames=$(printf "%02d\n" $frames) timecode="$hrs:$min:$sec:$frames" # timecode "01:13:34:54" 

这是脚本的缩写版本,已修复以提供您想要的输出:

 #!/bin/bash float=48.86 echo "You asked for $float; This is the price without taxes:" echo "scale=3; price=$float/1.18 +.005; scale=2; price/1 " | bc 

注意,向上舍入到最接近的整数相当于添加.5并采用下限或向下舍入(对于正数)。

此外,比例因子在操作时应用; 所以(这些是bc命令,你可以将它们粘贴到你的终端):

 float=48.86; rate=1.18; scale=2; p2=float/rate scale=3; p3=float/rate scale=4; p4=float/rate print "Compare: ",p2, " v ", p3, " v ", p4 Compare: 41.40 v 41.406 v 41.4067 # however, scale does not affect an entered value (nor addition) scale=0 a=.005 9/10 0 9/10+a .005 # let's try rounding scale=2 p2+a 41.405 p3+a 41.411 (p2+a)/1 41.40 (p3+a)/1 41.41 

按要求纯粹的bc实现

define ceil(x) { auto os,xx;x=-x;os=scale;scale=0 xx=x/1;if(xx>x).=xx-- scale=os;return(-xx) }

如果你把它放在一个名为functions.bc的文件中,那么你就可以了

echo 'ceil(3.1415)' | bc functions.bc

http://codd.net/gnu-bc/code/funcs.bc上的bc实现代码

 bc() { while : do while IFS='$\n' read i do /usr/bin/bc <<< "scale=2; $i" | sed 's/^\./0&/' done done }