如何与shell脚本中的浮点数进行比较

RIc*_*ams 33 shell shell-script arithmetic

我想在 shell 脚本中比较两个浮点数。以下代码不起作用:

#!/bin/bash   
min=12.45
val=10.35    
if (( $val < $min )) ; then    
  min=$val
fi
echo $min 
Run Code Online (Sandbox Code Playgroud)

Dan*_*und 44

Bash 不了解浮点运算。它将包含小数点的数字视为字符串。

请改用 awk 或 bc。

#!/bin/bash

min=12.45
val=10.35

if [ 1 -eq "$(echo "${val} < ${min}" | bc)" ]
then  
    min=${val}
fi

echo "$min"
Run Code Online (Sandbox Code Playgroud)

如果您打算进行大量数学运算,最好依靠 python 或 perl。


Pet*_*r.O 12

您可以使用包num-utils 进行简单的操作...

对于更严肃的数学,请参阅此链接...它描述了几个选项,例如。

  • R/Rscript(GNU R 统计计算和图形系统)
  • 八度(主要与 Matlab 兼容)
  • bc(GNU bc 任意精度计算器语言)

一个例子 numprocess

echo "123.456" | numprocess /+33.267,%2.33777/
# 67.0395291239087  
Run Code Online (Sandbox Code Playgroud)
A programs for dealing with numbers from the command line

The 'num-utils' are a set of programs for dealing with numbers from the
Unix command line. Much like the other Unix command line utilities like
grep, awk, sort, cut, etc. these utilities work on data from both
standard in and data from files.

Includes these programs:
 * numaverage: A program for calculating the average of numbers.
 * numbound: Finds the boundary numbers (min and max) of input.
 * numinterval: Shows the numeric intervals between each number in a sequence.
 * numnormalize: Normalizes a set of numbers between 0 and 1 by default.
 * numgrep: Like normal grep, but for sets of numbers.
 * numprocess: Do mathematical operations on numbers.
 * numsum: Add up all the numbers.
 * numrandom: Generate a random number from a given expression.
 * numrange: Generate a set of numbers in a range expression.
 * numround: Round each number according to its value.
Run Code Online (Sandbox Code Playgroud)

这是一个bash黑客......它在整数中添加前导 0 以使字符串从左到右的比较有意义。这段特殊的代码要求 minval实际上都有一个小数点和至少一个十进制数字。

min=12.45
val=10.35

MIN=0; VAL=1 # named array indexes, for clarity
IFS=.; tmp=($min $val); unset IFS 
tmp=($(printf -- "%09d.%s\n" ${tmp[@]}))
[[ ${tmp[VAL]} < ${tmp[MIN]} ]] && min=$val
echo min=$min
Run Code Online (Sandbox Code Playgroud)

输出:

min=10.35
Run Code Online (Sandbox Code Playgroud)


Gil*_*il' 12

对于浮点数(+-*/ 和比较)的简单计算,您可以使用 awk。

min=$(echo 12.45 10.35 | awk '{if ($1 < $2) print $1; else print $2}')
Run Code Online (Sandbox Code Playgroud)

或者,如果您有 ksh93 或 zsh(不是 bash),则可以使用支持浮点数的 shell 内置算法。

if ((min>val)); then ((val=min)); fi
Run Code Online (Sandbox Code Playgroud)

有关更高级的浮点计算,请查找bc。它实际上适用于任意精度的固定点数。

要处理数字表,请查找R示例)。


ata*_*ata 10

您可以分别检查整数和小数部分:

#!/bin/bash
min=12.45
val=12.35    
if (( ${val%%.*} < ${min%%.*} || ( ${val%%.*} == ${min%%.*} && ${val##*.} < ${min##*.} ) )) ; then    
    min=$val
fi
echo $min
Run Code Online (Sandbox Code Playgroud)

正如 fered 在评论中所说,只有当两个数字都有小数部分并且两个小数部分具有相同的位数时,它才有效。这是一个适用于整数或小数以及任何 bash 运算符的版本:

#!/bin/bash
shopt -s extglob
fcomp() {
    local oldIFS="$IFS" op=$2 x y digitx digity
    IFS='.' x=( ${1##+([0]|[-]|[+])}) y=( ${3##+([0]|[-]|[+])}) IFS="$oldIFS"
    while [[ "${x[1]}${y[1]}" =~ [^0] ]]; do
        digitx=${x[1]:0:1} digity=${y[1]:0:1}
        (( x[0] = x[0] * 10 + ${digitx:-0} , y[0] = y[0] * 10 + ${digity:-0} ))
        x[1]=${x[1]:1} y[1]=${y[1]:1} 
    done
    [[ ${1:0:1} == '-' ]] && (( x[0] *= -1 ))
    [[ ${3:0:1} == '-' ]] && (( y[0] *= -1 ))
    (( ${x:-0} $op ${y:-0} ))
}

for op in '==' '!=' '>' '<' '<=' '>='; do
    fcomp $1 $op $2 && echo "$1 $op $2"
done
Run Code Online (Sandbox Code Playgroud)

  • 如果没有大量工作,这无法解决(尝试比较“0.5”和“0.06”)。你最好使用已经理解十进制表示法的工具。 (4认同)

Vol*_*gel 6

使用数字排序

该命令sort有一个选项-g( --general-numeric-sort),可用于通过查找最小值或最大值来比较<“小于”或>“大于”。

这些示例正在寻找最小值:

$ printf '12.45\n10.35\n' | sort -g | head -1
10.35
Run Code Online (Sandbox Code Playgroud)

支持电子符号

它适用于非常通用的浮点数表示法,例如 E-Notation

$ printf '12.45E-10\n10.35\n' | sort -g | head -1
12.45E-10
Run Code Online (Sandbox Code Playgroud)

注意E-10,第一个数0.000000001245,确实小于10.35

可以比较无穷大

浮点标准IEEE754定义了一些特殊值。对于这些比较,有趣的是INF无穷大。还有负无穷大;两者都是标准中明确定义的值。

$ printf 'INF\n10.35\n' | sort -g | head -1
10.35
$ printf '-INF\n10.35\n' | sort -g | head -1
-INF
Run Code Online (Sandbox Code Playgroud)

要找到最大使用sort -gr而不是sort -g,颠倒排序顺序:

$ printf '12.45\n10.35\n' | sort -gr | head -1
12.45
Run Code Online (Sandbox Code Playgroud)

比较操作

要实现<(“小于”)比较,以便可以在if等中使用,请将最小值与其中一个值进行比较。如果最小值等于该值,则作为 text 比较,它小于另一个值:

$ a=12.45; b=10.35                                    
$ [ "$a" = "$(printf "$a\n$b\n" | sort -g | head -1)" ]
$ echo $?
1
$ a=12.45; b=100.35                                    
$ [ "$a" = "$(printf "$a\n$b\n" | sort -g | head -1)" ]
$ echo $?                                              
0
Run Code Online (Sandbox Code Playgroud)