【问题标题】:Problem with floating point comparison浮点比较的问题
【发布时间】:2011-08-28 19:27:27
【问题描述】:

我正在尝试检查我从文本文件中读取的值是否为零:

[[ $(echo $line | cut -d" " -f5) -gt 0 ]] && [[ $(echo $line | cut -d" " -f7 | bc -l) -eq 0 ]]

第一个条件没有问题,因为 f5 是整数。问题来自第二个条件。我收到此错误消息:

[[: 1.235: syntax error: invalid arithmetic operator (error token is ".235")

我尝试了一些在不同论坛中找到的建议,例如使用带双引号和不带双引号的echo $line | cut -d" " -f7 | bc -l 等。但是,错误仍然存​​在。 f7 为正数,保留 3 位小数。删除小数或近似不是一个选项,因为我需要结果完全为零 (0.000)。

【问题讨论】:

    标签: bash floating-point comparison numbers


    【解决方案1】:

    通常,您无法比较浮点数是否相等。这是因为十进制数的二进制表示不精确,并且会出现舍入错误。这是大多数人会给你的标准答案。

    在这种特定情况下,您实际上不需要比较浮点数,因为您只是在测试某些文本是否代表特定数字。由于您在 shell 中,您可以使用常规字符串与“0.000”进行比较 - 假设您的数据以这种方式四舍五入 - 或者使用带有 grep/egrep 的正则表达式。类似的东西

    egrep -q '0(|\.0+)'
    

    将匹配0、0.0、0.00等,并退出指示成功或失败,可以在周围的if语句中使用:

    if cut and pipe soup | egrep ... ; then
      ...
    fi
    

    【讨论】:

      【解决方案2】:

      改为使用字符串比较。替换:

      -eq 0
      

      与:

      = '0.000'
      

      TZ:

      评论中的脚本部分:

      for clus in $(ls *.cluster) ; do
          while read line ; do
              if [[ $(echo $line | cut -d" " -f11) -gt 0 ]] && [[ "$(echo $line | cut -d" " -f15 | bc -l)" = '0.000' ]] ; then
                  cat $(echo $line | cut -d" " -f6).pdb >> test/$(echo $line | cut -d" " -f2)_pisa.pdb
              fi
          done < $clus
      done
      

      我的伪 Python 解释:

      for clus in *.cluster:
          for line in clus:
              fields = line.split(' ')
              # field numbers are counting from 1 as in cut
              if int(field 11) > 0 and str(field 15) == '0.000':
                  fin_name = (field 6) + '.pdb'
                  fout_name = (field 2) + '_pisa.pdb'
                  cat fin_name >> fout_name
      

      这是你想要的吗?

      【讨论】:

      • 它不起作用。错误消失了。但是,由于出现错误,程序运行良好并产生了正确的输出。现在没有了。
      • 发布脚本?还是出错的部分?可能与此无关,因此您可能想发布一个新问题。
      • 对于 $(ls *.cluster) 中的集群; do while read line ;如果 [[ $(echo $line | cut -d" " -f11) -gt 0 ]] && [[ "$(echo $line | cut -d" " -f15 | bc -l)" = '0.000' ]] ;然后 cat $(echo $line | cut -d" " -f6).pdb >> test/$(echo $line | cut -d" " -f2)_pisa.pdb fi done
      • 现在可以使用了。有几个问题 ;-) [[ "$(echo "$line" | cut -c32-35)" != ' 0' ]] && [[ "$(echo "$line" | cut -c43-47) " == '0.000' ]] cat "$(echo "$line" | cut -c11-21)".pdb >> ./test/"$(echo "$line" | cut -c1-6)"_pisa .pdb
      猜你喜欢
      • 2011-02-03
      • 1970-01-01
      • 2010-12-09
      • 1970-01-01
      • 1970-01-01
      • 2011-10-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多