
첫 번째 숫자의 각 숫자의 합을 두 번째 숫자의 거듭제곱으로 계산하는 스크립트(script1.sh)를 작성하려고 합니다. 그래서
./script1.sh 12345 2
출력해야 한다55
(1+4+9+16+25=55이기 때문에)
또는./script1.sh 3706907995955475988644381 25
를 출력해야 합니다 3706907995955475988644381
.
스크립트를 작성했지만 어떤 경우에는 부정적인 결과가 나오며 어떻게 그런 일이 일어날 수 있는지 모르겠습니다.
예를 들어
./script1.sh 3706907995955475988644380 25
출력
-2119144605827694052
내 스크립트:
#!/bin/bash
sum=0
value=$1
arr=()
for ((i = 0; i < ${#value}; i++)); do
arr+=(${value:$i:1})
done
for x in "${arr[@]}"; do
sum=$(($sum+(x**$2)))
done
echo $sum
답변1
쉘 산술은 bash
C 컴파일러에서 지원하는 가장 넓은 정수 유형을 사용합니다. 대부분의 최신 시스템/C 컴파일러에서는 64비트 정수이므로 -9223372036854775808에서 9223372036854775807 범위를 "만" 포함하고 그 중 숫자는 줄 바꿈합니다. 이렇게 하려면 bc와 같은 다른 도구를 사용해야 합니다.
#!/bin/bash
num1=$1
num2=$2
sum=0
for (( i=0; i<${#num1}; i++ )); do
n=${num1:$i:1}
sum=$( bc <<<"$sum + $(bc <<<"${n}^$num2")" )
done
echo "$sum"
답변2
짧게awk
스크립트:
sum_powered.awk
스크립트:
#!/bin/awk -f
BEGIN{
split(ARGV[1], a, "");
pow = ARGV[2];
for (i in a) sum += a[i] ** pow;
print sum;
}
용법:
$ ./sum_powered.awk 12345 2
55
$ ./sum_powered.awk 3706907995955475988644381 25
3706907995955475217645568
새 파일에 실행 권한을 추가해야 할 수도 있습니다.앗실행 전 스크립트:
$ chmod +x sum_powered.awk
답변3
25자리( )의 결과를 갖는 수학을 수행하는 것은 3706907995955475988644381
확실히 대부분의 쉘 구현의 용량을 벗어납니다. 실제로 쉘 산술은 C 언어 산술과 매우 유사합니다. C 언어에서 부호 있는 정수는 오버플로가 있을 때 부호를 뒤집습니다. 64비트 시스템에서 사용하는 일반적인 가장 긴 시스템 정수는 63개의 이진수로 제한된 값을 갖습니다(다른 비트는 정수의 부호를 정의합니다). 따라서 이진수로 63개의 1 또는 16진수로 0efff ffff ffff ffff는 숫자 $( ( (1<<63) - 1 )) 또는 9223372036854775807 (19 자리). 음수 한도는 -9223372036854775808입니다.
25자리 숫자는 19자리 정수 안에 들어갈 수 없으므로 다음과 같이 오버플로됩니다.C 부호 있는 정수 오버플로: 기호를 변경하여(대부분의 컴퓨터에서):
$ echo "$(( 9223372036854775807 + 1 ))"
-9223372036854775808
기원전
(독립형) 유틸리티가 "임의 정밀도 수학"(미리 설정된 길이 제한이 없는 숫자)을 위해 제공할 수 있는 가장 낮은 수준의 언어는 bc입니다. BC에서는 전체 요구 사항을 실행하는 것이 어렵지 않습니다.
x=12345
y=2
scale=0;
s=0;
while (x>0) {
b=x%10;
x/=10;
s+=b^y
};
s
quit
이를 파일에 쓰고(이라고 가정 digpower.bc
) 다음과 같이 실행합니다.
$ bc -q digpower.bc
55
시간 변수를 처리하고 크기를 원래 값으로 되돌리는 함수만 포함하도록 전체 파일을 모핑합니다.
define d(x,y){
auto s,b,u; s=scale;
while (x>0) { b=x%10; x/=10; u+=b^y }
scale=s; return(u) };
이 경우 다음과 같이 bc를 호출합니다.
$ bc -q digpower.bc <<<"d(12345,2)"
55
$ echo "d(3706907995955475988644381,25)" | bc digpower.bc
3706907995955475988644381
파이썬
무제한(컴퓨터 메모리로만) 정수를 갖는 다음 상위 레벨 언어(공통 lisp 건너뛰기)는 Python입니다.
$ python3 -c 'x=12345;y=2;s=0;
while (x>0): b=x%10;x//=10;s+=b**y
print(s)'
55
대부분의 다른 언어는 awk
. 일부 언어에서는 플로트의 크기를 설정할 수 있습니다(이에 대한 자세한 내용은 후자에서 확인하세요).
앗
내부의 모든 숫자는 awk
부동 소수점으로 저장됩니다. 기본적으로 awk는 53비트 가수를 사용합니다. 53비트 가수의 일반적인 제한은 16자리입니다. 일부 특정 부동소수점에서는 17자리 또는 심지어 18자리 숫자가 정확할 수도 있습니다.
$ awk -vx=12345 -vy=2 'BEGIN{s=0;while(x>0){b=x%10;x=int(x/10);s+=b^y}; print(s)}'
55
그러나 (다른 값과 동일한 코드):
$ awk -vx=3706907995955475988644381 -vy=25 'BEGIN{s=0;while(x>0){b=x%10;x=int(x/10);s+=b^y}; print(s)}'
2989038141653481752100864
float로 내부 표현이 16자리 이후에 상당히 잘못되기 때문에 이는 분명히 잘못된 것입니다. 그냥 보여드리자면:
$ awk -vx=3706907995955475988644381 'BEGIN{print(x);print(x+0)}'
3706907995955475988644381
3706907995955475754516480
이러한 오류는 더 큰 오류로 이어집니다.
awk에 bignum이 컴파일된 경우 부동 소수점 가수의 비트 수를 늘리는 GNU awk의 대안이 있습니다(awk --version의 출력에 "GNU MPFR"이 포함됨).
$ awk -M -v PREC=100 -vx=3706907995955475988644381 -vy=25 'BEGIN{s=0;while(x>0){b=x%10;x=int(x/10);s+=b**y}; print(s)}'
3706907995955475988644381
25개의 십진수에는 대략 25*log(2)/log(10)
이진수 또는 83비트 가수가 필요합니다(정확한 답변은 설명하기가 상당히 깁니다). 100을 사용하면 충분한 여유가 있습니다.