쉘 스크립트에서 두 개의 부동 소수점 숫자를 비교하고 싶습니다. 다음 코드가 작동하지 않습니다.
#!/bin/bash
min=12.45
val=10.35
if (( $val < $min )) ; then
min=$val
fi
echo $min
답변
정수 부분과 분수 부분을 별도로 확인할 수 있습니다.
#!/bin/bash
min=12.45
val=12.35
if (( ${val%%.*} < ${min%%.*} || ( ${val%%.*} == ${min%%.*} && ${val##*.} < ${min##*.} ) )) ; then
min=$val
fi
echo $min
주석에서 언급했듯이 두 숫자에 소수 부분이 있고 두 소수 부분에 동일한 자릿수가있는 경우에만 작동합니다. 다음은 정수 또는 분수 및 모든 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
답변
Bash는 부동 소수점 산술을 이해하지 못합니다. 소수점을 포함하는 숫자를 문자열로 처리합니다.
대신 awk 또는 bc를 사용하십시오.
#!/bin/bash
min=12.45
val=10.35
if [ 1 -eq "$(echo "${val} < ${min}" | bc)" ]
then
min=${val}
fi
echo "$min"
많은 수학 연산을 수행하려면 파이썬이나 펄에 의존하는 것이 좋습니다.
답변
간단한 조작을 위해 패키지 num-utils 를 사용할 수 있습니다 …
더 심각한 수학에 대해서는 이 링크를 참조하십시오 . 예를 들어 몇 가지 옵션을 설명합니다.
- R / Rscript (GNU R 통계 계산 및 그래픽 시스템)
- 옥타브 (대부분 Matlab 호환)
- bc (GNU bc 임의 정밀도 계산기 언어)
의 예 numprocess
echo "123.456" | numprocess /+33.267,%2.33777/
# 67.0395291239087
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.
여기에 bash
해킹이 있습니다 … 문자열을 왼쪽에서 오른쪽으로 비교하기 위해 정수에 선행 0을 추가합니다. 이 특정 코드 조각은 min 과 val 모두 실제로 소수점과 하나 이상의 10 진수를 가져야합니다.
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
산출:
min=10.35
답변
부동 소수점 숫자 (+-* / 및 비교)에 대한 간단한 계산을 위해 awk를 사용할 수 있습니다.
min=$(echo 12.45 10.35 | awk '{if ($1 < $2) print $1; else print $2}')
또는 ksh93 또는 zsh (bash가 아닌)를 사용하는 경우 부동 소수점 숫자를 지원하는 쉘의 내장 산술을 사용할 수 있습니다.
if ((min>val)); then ((val=min)); fi
고급 부동 소수점 계산에 대해서는 bc를 찾아보십시오 . 실제로 임의의 정밀도 수정 점 번호에서 작동합니다.
답변
숫자 정렬 사용
이 명령 sort
에는 최소값 또는 최대 값을 찾아 “보다 작음”또는 “보다 큼” 을 비교하는 데 사용할 수 있는 옵션 -g
( --general-numeric-sort
)이 있습니다 .<
>
이 예제는 최소값을 찾습니다.
$ printf '12.45\n10.35\n' | sort -g | head -1
10.35
전자 표기법 지원
전자 표기법과 같이 부동 소수점 숫자의 일반적인 표기법으로 작동합니다.
$ printf '12.45E-10\n10.35\n' | sort -g | head -1
12.45E-10
를 참고 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
최대 사용 찾으려면 sort -gr
대신을 sort -g
정렬 순서를 반대로 :
$ printf '12.45\n10.35\n' | sort -gr | head -1
12.45
비교 조작
<
( “보다 작음”) 비교 를 구현하려면 if
등을 사용할 수 있으므로 최소값 중 하나와 비교하십시오. 텍스트와 비교 하여 최소값이 값과 같으면 다른 값보다 작습니다.
$ 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
답변
부동 소수점 산술을 기본적으로 지원하는 ksh
( ksh93
정확하게) 또는를 사용하십시오 zsh
.
$ cat test.ksh
#!/bin/ksh
min=12.45
val=10.35
if (( $val < $min )) ; then
min=$val
fi
echo "$min"
$ ./test.ksh
10.35
편집 : 미안, ksh93
이미 보고 싶었습니다 . 첫 번째 질문에 게시 된 스크립트를 명확하게하기 위해 내 대답을 유지하면 셸 스위치 외부에서 변경하지 않고 사용할 수 있습니다.
Edit2 : ksh93
변수 내용이 로케일과 일치해야합니다 (예 : 프랑스어 로케일의 경우 점 대신 쉼표를 사용해야 함).
...
min=12,45
val=10,35
...
보다 강력한 해결책은 스크립트 시작 부분에 사용자의 로캘에 관계없이 작동하도록 로캘을 설정하는 것입니다.
...
export LC_ALL=C
min=12.45
val=10.35
...
답변
min=$(echo "${min}sa ${val}d la <a p" | dc)
사용하는 dc
을 계산기 s
의 값을 찢고 $min
레지스터 a
와 d
값을 uplicates $val
주요 실행 스택의 상단에. 그런 다음 l
내용을 a
스택 상단에 흘려 보냅니다 .
${min} ${val} ${val}
이 <
스택은 스택에서 상위 2 개 항목을 팝하여 비교합니다. 따라서 스택은 다음과 같습니다.
${val}
맨 위 항목이 맨 위 항목보다 작 으면 맨 위에 내용을 푸시 a
하므로 스택은 다음과 같습니다.
${min} ${val}
그렇지 않으면 아무것도하지 않으며 스택은 여전히 다음과 같습니다.
${val}
그런 다음 p
상단 스택 항목을 헹구십시오.
그래서 당신의 문제를 위해 :
min=12.45
val=12.35
echo "${min}sa ${val}d la <a p" | dc
###OUTPUT
12.35
그러나:
min=12.45
val=12.55
echo "${min}sa ${val}d la <a p" | dc
###OUTPUT
12.45