Bash에서 두 부동소수점 숫자를 비교하려면 어떻게 해야 하나요?
저는 Bash 스크립트 내에서 두 부동소수점 숫자를 비교하려고 노력하고 있습니다.두 가지 변수가 있습니다.
let num1=3.17648e-22
let num2=1.5
이 두 숫자를 간단하게 비교해 보겠습니다.
st=`echo "$num1 < $num2" | bc`
if [ $st -eq 1]; then
echo -e "$num1 < $num2"
else
echo -e "$num1 >= $num2"
fi
유감스럽게도 num1의 올바른 처리에 문제가 있습니다.이러한 num1은 e포맷일 수 있습니다.
보다 편리하게
이는 Bash의 숫자 컨텍스트를 사용하여 보다 편리하게 수행할 수 있습니다.
if (( $(echo "$num1 > $num2" |bc -l) )); then
…
fi
설명.
명령어를 연결bc
는 1 0.1의 합니다.
" "-l
--mathlib
; ; ; ; ; ;의
사이에 (( ))
거짓이다
bc
기본 계산기 패키지가 설치됩니다.
주의: 지수 표기법은 다음과 같이 기술해야 합니다.*10^
아니다E
,도 아니다e
.
예를 들어 다음과 같습니다.
$ echo "1*10^3==1000" |bc
1
반면에.
$ echo "1E3==1000" |bc
0
를 bc
여기에서는 제한에 대해 설명합니다.
는 정수하지만 Bash는 할 수 .bc
츠키다
$ num1=3.17648E-22
$ num2=1.5
$ echo $num1'>'$num2 | bc -l
0
$ echo $num2'>'$num1 | bc -l
1
지수 기호는 대문자로 해야 합니다.
정수 이외의 수학에는 AWK를 사용하는 것이 좋습니다.다음 Bash 유틸리티 함수를 사용할 수 있습니다.
numCompare() {
awk -v n1="$1" -v n2="$2" 'BEGIN {printf "%s " (n1<n2?"<":">=") " %s\n", n1, n2}'
}
그리고 그것을 다음과 같이 부릅니다.
numCompare 5.65 3.14e-22
5.65 >= 3.14e-22
numCompare 5.65e-23 3.14e-22
5.65e-23 < 3.14e-22
numCompare 3.145678 3.145679
3.145678 < 3.145679
지수 표기법, 선행 또는 후행 0 없이 플로트를 비교하는 순수 Bash 솔루션:
if [ ${FOO%.*} -eq ${BAR%.*} ] && [ ${FOO#*.} \> ${BAR#*.} ] || [ ${FOO%.*} -gt ${BAR%.*} ]; then
echo "${FOO} > ${BAR}";
else
echo "${FOO} <= ${BAR}";
fi
논리 연산자의 순서가 중요합니다.정수부분을 숫자로 비교하고 소수부분을 문자열로 의도적으로 비교한다.변수는 이 방법을 사용하여 정수 부분과 소수 부분으로 나뉩니다.
플로트와 정수(점 없음)는 비교하지 않습니다.
다음의 경우, AWK 를 Bash 와 조합해 사용할 수 있습니다.
if awk "BEGIN {exit !($d1 >= $d2)}"; then
echo "yes"
else
echo "no"
fi
grep 2.20이 버전 2.6보다 큰지 확인하는 등 패키지 버전 번호를 비교할 때는 주의하십시오.
$ awk 'BEGIN { print (2.20 >= 2.6) ? "YES" : "NO" }'
NO
$ awk 'BEGIN { print (2.2 >= 2.6) ? "YES" : "NO" }'
NO
$ awk 'BEGIN { print (2.60 == 2.6) ? "YES" : "NO" }'
YES
이러한 문제를 셸/AWK 기능으로 해결했습니다.
# Get version of GNU tool
toolversion() {
local prog="$1" operator="$2" value="$3" version
version=$($prog --version | awk '{print $NF; exit}')
awk -vv1="$version" -vv2="$value" 'BEGIN {
split(v1, a, /\./); split(v2, b, /\./);
if (a[1] == b[1]) {
exit (a[2] '$operator' b[2]) ? 0 : 1
}
else {
exit (a[1] '$operator' b[1]) ? 0 : 1
}
}'
}
if toolversion grep '>=' 2.6; then
# Do something awesome
fi
를 모두 포함하는 대/소문자 양쪽)을 한 가능한 표기법을 .12.00e4
if (( $(bc -l <<< "${value1/e/E} < ${value2/e/E}") ))
then
echo "$value1 is smaller than $value2"
fi
물론 실제로 부동소수점 산술이 필요하지 않은 경우, 예를 들어 항상 정확하게 소수점 두 자리만 있는 달러 값에 대한 산술만 필요할 경우 점을 찍고(실효적으로 100을 곱한 값) 결과 정수를 비교할 수 있습니다.
if [[ $((10#${num1/.})) < $((10#${num2/.})) ]]; then
...
따라서 두 값의 소수 자릿수가 동일한지 확인해야 합니다.
아래 편집된 코드를 확인하십시오.
#!/bin/bash
export num1=(3.17648*e-22)
export num2=1.5
st=$((`echo "$num1 < $num2"| bc`))
if [ $st -eq 1 ]
then
echo -e "$num1 < $num2"
else
echo -e "$num1 >= $num2"
fi
이거 잘 되네.
num1=0.555
num2=2.555
if [ `echo "$num1>$num2"|bc` -eq 1 ]; then
echo "$num1 is greater then $num2"
else
echo "$num2 is greater then $num1"
fi
여기서 나온 답을 사용해서 함수에 넣었어요.다음과 같이 사용할 수 있습니다.
is_first_floating_number_bigger 1.5 1.2
result="${__FUNCTION_RETURN}"
콜이 되면, 「」는 「 」echo $result
되다1
그 이외의 경우는 「」로 합니다.0
.
기능:
is_first_floating_number_bigger () {
number1="$1"
number2="$2"
[ ${number1%.*} -eq ${number2%.*} ] && [ ${number1#*.} \> ${number2#*.} ] || [ ${number1%.*} -gt ${number2%.*} ];
result=$?
if [ "$result" -eq 0 ]; then result=1; else result=0; fi
__FUNCTION_RETURN="${result}"
}
또는 디버깅 출력이 있는 버전:
is_first_floating_number_bigger () {
number1="$1"
number2="$2"
echo "... is_first_floating_number_bigger: comparing ${number1} with ${number2} (to check if the first one is bigger)"
[ ${number1%.*} -eq ${number2%.*} ] && [ ${number1#*.} \> ${number2#*.} ] || [ ${number1%.*} -gt ${number2%.*} ];
result=$?
if [ "$result" -eq 0 ]; then result=1; else result=0; fi
echo "... is_first_floating_number_bigger: result is: ${result}"
if [ "$result" -eq 0 ]; then
echo "... is_first_floating_number_bigger: ${number1} is not bigger than ${number2}"
else
echo "... is_first_floating_number_bigger: ${number1} is bigger than ${number2}"
fi
__FUNCTION_RETURN="${result}"
}
은 따로따로 하세요..sh
하다
. /path/to/the/new-file.sh
AWK와 그와 같은 툴 (널 쳐다보고 있어)sed
는 오래된 있기 수 코드는 읽기-절대 언어로 쓰여져 있기 때문에 모두가 만질 수 없습니다.
또는 코드 유지 보수 최적화보다 CPU 사용률 최적화를 우선시해야 하는 비교적 드문 프로젝트입니다.그렇다면 계속하세요
그렇지 않다면, 대신 Python과 같이 읽기 쉽고 명시적인 것을 사용하십시오.당신의 동료 프로그래머들과 미래의 자신이 당신에게 감사할 것입니다.Python 코드는 다른 모든 코드와 마찬가지로 Bash와 인라인으로 사용할 수 있습니다.
num1=3.17648E-22
num2=1.5
if python -c "exit(0 if $num1 < $num2 else 1)"; then
echo "yes, $num1 < $num2"
else
echo "no, $num1 >= $num2"
fi
단순성과 명확성을 위해 AWK를 사용하여 계산하면 됩니다.이것은 표준 Unix 툴이기 때문에 bc와 마찬가지로 존재할 가능성이 높기 때문에 구문적으로 작업하기 쉬워집니다.
이 질문의 경우:
$ cat tst.sh
#!/bin/bash
num1=3.17648e-22
num2=1.5
awk -v num1="$num1" -v num2="$num2" '
BEGIN {
print "num1", (num1 < num2 ? "<" : ">="), "num2"
}
'
$ ./tst.sh
num1 < num2
그리고 이 질문의 중복으로 종결된 다른 질문:
$ cat tst.sh
#!/bin/bash
read -p "Operator: " operator
read -p "First number: " ch1
read -p "Second number: " ch2
awk -v ch1="$ch1" -v ch2="$ch2" -v op="$operator" '
BEGIN {
if ( ( op == "/" ) && ( ch2 == 0 ) ) {
print "Nope..."
}
else {
print ch1 '"$operator"' ch2
}
}
'
$ ./tst.sh
Operator: /
First number: 4.5
Second number: 2
2.25
$ ./tst.sh
Operator: /
First number: 4.5
Second number: 0
Nope...
4.5: 구문 오류: 잘못된 산술 연산자(오류 토큰은 ".5"입니다)에 대한 답변으로 이 글을 올렸습니다. 그러나 코드는 여전히 작동하는 것 같습니다. 왜? 이 질문의 중복으로 닫혔을 때, 여기에도 해당됩니다.
이 스크립트는 설치된 Grails 버전이 필요한 최소 버전보다 큰지 확인하는 데 도움이 될 수 있습니다.
#!/bin/bash
min=1.4
current=`echo $(grails --version | head -n 2 | awk '{print $NF}' | cut -c 1-3)`
if [ 1 -eq `echo "${current} < ${min}" | bc` ]
then
echo "Yo, you have an older version of Grails."
else
echo "Hurray, you have the latest version"
fi
KornShell을 사용합니다.Bash에서는 소수점 부분을 별도로 비교해야 할 수 있습니다.
#!/bin/ksh
X=0.2
Y=0.2
echo $X
echo $Y
if [[ $X -lt $Y ]]
then
echo "X is less than Y"
elif [[ $X -gt $Y ]]
then
echo "X is greater than Y"
elif [[ $X -eq $Y ]]
then
echo "X is equal to Y"
fi
사용방법:
VAL_TO_CHECK="1.00001"
if [ $(awk '{printf($1 >= $2) ? 1 : 0}' <<<" $VAL_TO_CHECK 1 ") -eq 1 ] ; then
echo "$VAL_TO_CHECK >= 1"
else
echo "$VAL_TO_CHECK < 1"
fi
Java를 지원하는 Bash 돌연변이 bashj를 사용하면 다음과 같이 쓸 수 있습니다(읽기 쉽습니다).
#!/usr/bin/bashj
#!java
static int doubleCompare(double a,double b) {return((a>b) ? 1 : (a<b) ? -1 : 0);}
#!bashj
num1=3.17648e-22
num2=1.5
comp=j.doubleCompare($num1,$num2)
if [ $comp == 0 ] ; then echo "Equal" ; fi
if [ $comp == 1 ] ; then echo "$num1 > $num2" ; fi
if [ $comp == -1 ] ; then echo "$num2 > $num1" ; fi
물론 bashj Bash/Java 하이브리드는 더 많은 것을 제공합니다.
매우 심플한 Perl 솔루션:
$ num1=3.2E8
$ num2=2.5E9
$ perl -e "print $num2 > $num1? 'true' : 'false', qq(\n);"
true
$ perl -e "print $num2 < $num1? 'true' : 'false', qq(\n);"
false
이는 perl이 과학적 수치표현의 'E' 표기를 실제로 이해하고 있음을 증명합니다.
$ perl -e "print $num1, qq(\n);"
320000000
셸 스크립트에 'if' 스테이트먼트가 필요한 경우 perl에서 exit 명령을 사용합니다.
$ if perl -e "exit ($num1 > $num2? 0 : 1);"; then echo true; else echo false; fi
false
셸 스크립트에서 0을 반환하는 명령어는 성공하며 if 조건을 통과시킵니다(따라서 if-clause가 실행됩니다).기타 0 이외의 반환값은 장애를 의미합니다.
AWK보다 조금 더 빠르고 필요한 접근법이 하나 있습니다.bc
인스톨 합니다.이용하다sort
의 플로트 번호 정렬 기능:
A=1280.4
B=9.325
LOW=$(sort -n <<< "$A"$'\n'"$B" | head -1)
if [[ "$LOW" == "$A" ]]; then
echo "A <= B"
else
echo "A >= B"
fi
물론 같은 숫자에 대해서는 효과가 없습니다.
를 교환해 주세요.echo
printf 포함(플로트 인식):
st=$( printf '%50G < %50G\n' "$num1" "$num2" | bc -l )
원라이너 솔루션
변수가 두 개 있다고 가정합니다.A
그리고.B
,
echo "($A > $B) * $B + ($A < $B) * $A" | bc
여기 있습니다.gawk+GMP
보다 광범위한 잠재적 투입을 고려하는 기반 접근법:
echo " 5.65e-23 3.14e-22\n
5.65 3.14e-2203\n
3.145678 3.145679\n
3.25353E+9293 325353e9288\n
3.14159e+200000000001 3.1415899999999999999999E200000000001\n
100000 100000.0\n
4096 4096" \
\
| gawk -v PREC=9999999 -nMbe '
NF+=OFS=sprintf(" %s ",
(+($!_=sprintf("%24s",$!_)<+$NF) \
? "<" \
: (+$NF<+$!_) \
? ">" \
: (int(+$!_)==(__=int(+$NF)))*\
(__==+$NF)*index($!_,$NF ) \
? "=" \
: "\342\211\210")' | ecp
5.65e-23 < 3.14e-22
5.65 > 3.14e-2203
3.145678 < 3.145679
3.25353E+9293 ≈ 325353e9288
3.14159e+200000000001 ≈ 3.1415899999999999999999E200000000001
100000 ≈ 100000.0
4096 = 4096
좀 더 명확한 케이스에 대해서는
- 보다 적은
<
, - 보다 크다
>
, 또는 - 와 꼭 같은
=
(현재로서는 정수 케이스는 제외)
비교적 애매한 경우, 출력합니다.Unicode
성격U+2248 ≈ ALMOST EQUAL TO
어떤 대가를 치르더라도 해결하려고 하지 않고 말이죠.
대부분의 경우 필요 없습니다.PREC
1000만이나 되는 것 같다PREC = 32767
일반적인 상황에서 발생하는 대부분의 시나리오에 적합합니다.
언급URL : https://stackoverflow.com/questions/8654051/how-can-i-compare-two-floating-point-numbers-in-bash
'programing' 카테고리의 다른 글
C#의 Excel 셀에 새 행을 프로그래밍 방식으로 삽입하려면 어떻게 해야 합니까? (0) | 2023.04.21 |
---|---|
빌드 실패의 원인을 오류 또는 경고 없이 찾는 방법 (0) | 2023.04.21 |
Apache POI와 함께 날짜가 있는 Excel 셀을 읽는 방법 (0) | 2023.04.21 |
TSQL에서의 COALESCE 기능 (0) | 2023.04.21 |
SQL Server에서 전달의 첫 번째 날과 마지막 날(타임스탬프 포함)을 가져오는 방법 (0) | 2023.04.21 |