기원전

기원전

첫 번째 숫자의 각 숫자의 합을 두 번째 숫자의 거듭제곱으로 계산하는 스크립트(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

쉘 산술은 bashC 컴파일러에서 지원하는 가장 넓은 정수 유형을 사용합니다. 대부분의 최신 시스템/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을 사용하면 충분한 여유가 있습니다.

관련 정보