【问题标题】:Division in script and floating-point脚本和浮点中的除法
【发布时间】:2012-08-27 17:57:51
【问题描述】:

我想在我的脚本中做如下操作:

1 - ((m - 20) / 34)

我想将此操作的结果分配给另一个变量。我希望我的脚本使用浮点数学。例如,对于 m = 34:

results = 1 - ((34 - 20) / 34) == 0.588

【问题讨论】:

    标签: bash shell


    【解决方案1】:

    您可以使用bc 计算器。如果您将 scale 从默认值 0 设置为增加,它将使用小数(不是二进制浮点数)进行任意精度数学运算:

    $ m=34
    $ bc <<< "scale = 10; 1 - (($m - 20) / 34)"
    .5882352942
    

    -l 选项将加载标准数学库并将比例默认为 20:

    $ bc -l <<< "1 - (($m - 20) / 34)"
    .58823529411764705883
    

    然后您可以使用 printf 来格式化输出,如果您愿意的话:

    printf "%.3f\n" "$(bc -l ...)"
    

    【讨论】:

    • @rubo77 我做了这样的事情let fail_percent=0 let total=$((pass_count+fail_count)) printf "Fail percentage is %f\n" $(bc -l &lt;&lt;&lt; "($fail_count / $total)") 这里total=16和fail_count=15,我得到的答案是0.93750000000000000000,但它带有一个错误,因为我给出的printf无效数字# !/bin/bash 在脚本开头...知道为什么会出错吗?
    • 使用printf '%f\n' $(bc -l &lt;&lt;&lt; 1.2)我得到错误bash: printf: 1.2: Ungültige Zahl.
    【解决方案2】:

    Bash 不进行浮点数学运算。您可以使用 awk 或 bc 来处理此问题。这是一个 awk 示例:

    $ m=34; awk -v m=$m 'BEGIN { print 1 - ((m - 20) / 34) }'
    0.588235
    

    将输出分配给变量:

    var=$(awk -v m=$m 'BEGIN { print 1 - ((m - 20) / 34) }')
    

    【讨论】:

    • 这对我很有用。我稍微改了一下,因为 awk 脚本很简单,你不需要用单引号保护它。这是一个稍微简单的版本:$ m=34; awk "BEGIN { print 1 - (($m - 20) / 34) }"。我只是将单引号更改为双引号,因此 bash 将为我插入 $m。
    【解决方案3】:

    教 bash,例如带浮点结果的整数除法:

    #!/bin/bash
    
    div ()  # Arguments: dividend and divisor
    {
            if [ $2 -eq 0 ]; then echo division by 0; exit; fi
            local p=12                            # precision
            local c=${c:-0}                       # precision counter
            local d=.                             # decimal separator
            local r=$(($1/$2)); echo -n $r        # result of division
            local m=$(($r*$2))
            [ $c -eq 0 ] && [ $m -ne $1 ] && echo -n $d
            [ $1 -eq $m ] || [ $c -eq $p ] && echo && return
            local e=$(($1-$m))
            c=$(($c+1))
            div $(($e*10)) $2
    }  
    
        result=$(div 1080 633)                  # write to variable
        echo $result
    
        result=$(div 7 34)
        echo $result
    
        result=$(div 8 32)
        echo $result
    
        result=$(div 246891510 2)
        echo $result
    
        result=$(div 5000000 177)
        echo $result
    

    输出:

        1.706161137440
        0.205882352941
        0.25
        123445755
        28248.587570621468
    

    【讨论】:

    • 非常好。如果将 let c=c+1 更改为 c=$(($c+1)),这甚至会符合 POSIX,但这种递归看起来很昂贵......
    【解决方案4】:
    echo $a/$b|bc -l
    

    给出结果。

    例子:

    read a b
    echo $a/$b|bc -l
    

    输入 a & b 值为 10 3,得到 3.3333333333

    如果要将值存储在另一个变量中,请使用代码

    read a b
    c=`echo $a/$b|bc -l`
    echo $c
    

    它也给出了与上面相同的结果。 试试看……

    【讨论】:

      【解决方案5】:

      我知道这是一个旧线程,但这似乎是一个有趣的项目,无需使用bc 或调用递归即可解决。我确信它可以改进,但这最大限度地发挥了我的技能。

      numerator=5
      denominator=7 # - 0 -> returns "undef"
      decimal_places=4 # - 0 -> same as echo $(( $numerator / $denominator ))
      _result_sign=""
      let _dp_exp=10**decimal_places
      if [ $denominator -eq 0 ]; then _div_result_int_large=0; else let _div_result_int_large=$((numerator * _dp_exp / denominator)); fi
      if [ $_div_result_int_large -lt 0 ]; then let _div_result_int_large=$(( _div_result_int_large * -1 )); _result_sign="-"; fi
      let _div_result_int=$((_div_result_int_large / _dp_exp))
      let _div_result_mant=$((_div_result_int_large - _div_result_int * _dp_exp))
      let _dp_lzeros=$((decimal_places - ${#_div_result_mant}))
      printf -v _div_result_mant_padded "%.${_dp_lzeros}d$_div_result_mant"
      div_result="$_result_sign$_div_result_int"
      if [ $decimal_places -gt 0 ]; then div_result="$_result_sign$_div_result_int.$_div_result_mant_padded"; fi
      if [ $denominator -eq 0 ]; then div_result="undef"; fi
      echo $div_result
      

      示例输出:

      numerator=5
      denominator=7
      decimal_places=5
      -> 0.71428
      
      numerator=250
      denominator=13
      decimal_places=0
      -> 19
      
      numerator=-5
      denominator=6
      decimal_places=2
      -> -0.83
      
      numerator=3
      denominator=0 # - uh-oh
      decimal_places=2 # - can be anything, in this case
      -> undef
      

      【讨论】:

        【解决方案6】:

        使用这个脚本用喜欢的编辑器打开这个文件,比如:

        $ sudo vim /usr/bin/div
        

        然后粘贴这段代码:

        #!/bin/bash
        # Author: Danial Rikhteh Garan (danial.rikhtehgaran@gmail.com)
        
        if [[ -z "$1" ]] || [[ -z "$2" ]]; then
            echo "Please input two number"
            echo "for 100/50 use: div 10 50"
            exit 1;
        fi
        
        div=$(echo "$1/$2" | bc -l);
        echo 0$div | sed 's/[0]*$//g'
        

        现在将其更改为 755:

        $ sudo chmod 755 /usr/bin/div
        

        现在使用它:

        $ div 5 100
        0.05
        

        在你的脚本中你可以使用这个:

        var=$(div 5 100);
        echo "$var"
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-05-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多