나는 첫 번째 숫자의 각 숫자의 합을 제공하고 두 번째 숫자의 거듭제곱을 계산하는 스크립트(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
기원전
a(독립형) 유틸리티가 "임의의 정밀도 수학"(미리 설정된 길이 제한이 없는 숫자)을 제공할 수 있는 가장 낮은 수준의 언어는 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
부동 소수점 숫자의 내부 표현이 16자리 이후에는 완전히 잘못되었기 때문에 이것은 분명히 잘못된 것입니다. 그냥 보여드리자면:
$ awk -vx=3706907995955475988644381 'BEGIN{print(x);print(x+0)}'
3706907995955475988644381
3706907995955475754516480
이런 실수는 더 큰 실수로 이어진다.
awk가 bignum으로 컴파일된 경우(awk --version의 출력에 "GNU MPFR"이 포함됨) GNU awk의 대안은 부동 소수점 가수의 수를 늘리는 것입니다.
$ 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을 사용하면 충분한 마진이 제공됩니다.