이 특별한 while 루프는 숫자 20까지만 작동한다는 것을 인정합니다. 그 이후에는 잘못된 답변이 제공되기 시작했지만 그 이유를 이해하지 못합니다.
#!/bin/bash
n=$1
[ "$n" == "" ] && echo Please give a number and try again && exit
factorial=1 ; j=1
while [ $j -le $n ]
do
factorial=$(( $factorial * $j ))
j=$(( $j + 1 ))
done
echo The factorial of $n, "$n"'!' = $factorial
exit 0
21을 인수로 제공하면 -4249290049419214848을 얻게 됩니다. 배쉬 문제일까요? 아래에서 계승 계산을 시도했지만 동일한 잘못된 답을 얻었습니다. 대답은 다음과 같습니다: 51090942171709440000
echo $(( 2432902008176640000 * 21 ))
답변1
Bash는 대부분의 시스템에서 부호 있는 64비트 정수를 사용합니다. bc
이 문제를 해결하려면 또 다른 유사한 도구가 필요합니다 .
이는 bash를 사용하여 가질 수 있는 최대 수가 이고 이 수를 초과한다는 것을 의미 2^63-1
합니다 9,223,372,036,854,775,807
.
awk 'BEGIN{print 2432902008176640000 * 21}'
51090942171709440000 #--> 51,090,942,171,709,440,000
답변2
doneal24가 말했듯이 떠나야 할 수도 있습니다 bc
.
Fact.bc라는 파일에 다음 내용을 추가합니다.
define f (x) {
if (x <= 1) return (1);
return (f(x-1) * x);
}
이제 파일을 제공하여 bc에서 호출할 수 있습니다.
$>bc fact.bc <<< "scale=50;f(200)"
78865786736479050355236321393218506229513597768717326329474253324435\
94499634033429203042840119846239041772121389196388302576427902426371\
05061926624952829931113462857270763317237396988943922445621451664240\
25403329186413122742829485327752424240757390324032125740557956866022\
60319041703240623517008587961789222227896237038973747200000000000000\
00000000000000000000000000000000000
답변3
이를 정수 오버플로 오류라고 합니다.@doneal24의 답변에 따르면 Bash는 64비트 정수를 사용하지만 설명에서는 무슨 일이 일어나고 있는지 더 쉽게 보여주기 위해 8비트 정수를 사용하겠습니다.
8비트 정수는 8비트 내에 양수 또는 음수를 저장하지만 모든 비트가 정수 값을 저장하는 것은 아닙니다. 숫자의 첫 번째 비트인 부호 비트는 숫자가 양수인지 음수인지를 나타냅니다. "0", 음수의 경우 "1"), 다음 7자리는 표준 이진 표기법을 사용하여 관련 숫자 값을 형성합니다.
예를 들어 값이 1인 정수는 다음과 같습니다.
0000 0001
그런 다음 프로그램 실행을 시작하고 다음 계승을 계산하는 데 필요한 값을 곱하여 해당 정수 값을 늘리기 시작할 수 있습니다. 따라서 여기에 2를 곱하고 프로세스를 반복하기 시작하면 다음과 같은 결과를 얻게 됩니다.
0000 0001×0000 0010 = 0000 0010
0000 0010×0000 0011 = 0000 1010
0000 1010×0000 0100 = 0001 1000
0001 1000×0000 0101 = 0111 1000
이제 우리는 매우 가까워졌습니다. 다음 반복에서는 오류가 발생합니다.
0111 1000×0000 0110 = 0010 1101 0000
정수 값을 저장하기 위해 할당된 8비트가 오버플로된다는 것을 알 수 있습니다. 이는 정수가 저장되기 전에 메모리 위치에 저장된 모든 것을 덮어쓴다는 의미이며, 이는 컴퓨터 프로세스를 손상시킬 수 있으므로 나쁜 소식입니다. 과거에도 비슷한 보안 취약점을 이용해 컴퓨터를 공격한 적이 있습니다.
그런데 정수 위치에 저장된 8비트가 "1101 0000"이라는 것도 알 수 있다. 이는 컴퓨터가 해당 값을 해석할 때 첫 번째 비트를 음수를 나타내는 부호 비트로 읽은 다음 숫자의 나머지 부분을 "101 0000" 또는 80으로 읽어서 연산의 값은 "입니다. -80".