테스트 한계:

테스트 한계:

이것은 탐구적인 질문입니다. 즉, 이 질문이 무엇에 관한 것인지 완전히 확신할 수는 없지만 Bash의 최대 정수와 관련이 있다고 생각합니다. 어쨌든 명확하게 정의하겠습니다.

$ echo $((1<<8))
256

조금 움직여 정수를 생성합니다. 얼마나 멀리 갈 수 있나요?

$ echo $((1<<80000))
1

분명히 우리는 아직 이 지점에 도달하지 않았습니다. (1은 예상치 못한 일이었습니다. 다시 설명하겠습니다.) 그러나,

$ echo $((1<<1022))
4611686018427387904

여전히 긍정적입니다. 그러나 이것은 아닙니다:

$ echo $((1<<1023))
-9223372036854775808

그리고 더 나아가,

$ echo $((1<<1024))
1

왜 1입니까?왜 다음과 같은 상황이 발생합니까?

$ echo $((1<<1025))
2
$ echo $((1<<1026))
4

이 시리즈를 분석하고 싶은 사람이 있나요?

고쳐 쓰다

내 컴퓨터:

$ uname -a
Linux tomas-Latitude-E4200 4.4.0-47-generic #68-Ubuntu SMP Wed Oct 26 19:39:52 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux

답변1

불다변수를 사용하여 intmax_t산술 연산 수행. 귀하의 시스템에서는 길이가 64비트이므로 다음과 같습니다.

$ echo $((1<<62))
4611686018427387904

이것은

100000000000000000000000000000000000000000000000000000000000000

이진 형식(1 뒤에 62개의 0이 옴). 다시 이동:

$ echo $((1<<63))
-9223372036854775808

이것은

1000000000000000000000000000000000000000000000000000000000000000

이진수(0 63개), 2의 보수 산술.

표현 가능한 가장 큰 정수를 얻으려면 1을 뺍니다.

$ echo $(((1<<63)-1))
9223372036854775807

이것은

111111111111111111111111111111111111111111111111111111111111111

바이너리 형태로.

지적한대로이르카초~의답변, 오프셋 모듈로 64를 사용하여 64비트로 이동x86CPU(사용 여부에 관계없이 RCL) SHL는 다음과 같이 나타나는 동작을 설명합니다.

$ echo $((1<<64))
1

와 동일 합니다 $((1<<0)).​​$((1<<1025))$((1<<1))$((1<<1026))$((1<<2))

유형 정의와 최대값은 다음에서 확인할 수 있습니다.stdint.h;시스템에서:

/* Largest integral types.  */
#if __WORDSIZE == 64
typedef long int                intmax_t;
typedef unsigned long int       uintmax_t;
#else
__extension__
typedef long long int           intmax_t;
__extension__
typedef unsigned long long int  uintmax_t;
#endif

/* Minimum for largest signed integral type.  */
# define INTMAX_MIN             (-__INT64_C(9223372036854775807)-1)
/* Maximum for largest signed integral type.  */
# define INTMAX_MAX             (__INT64_C(9223372036854775807))

답변2

2.05b의 CHANGES문서 bash:

제이. 이제 쉘은 long 대신 시스템이 지원하는 최대 정수 크기(intmax_t)를 사용하여 산술을 수행합니다.

x86_64 시스템의 intmax_t부호 있는 64비트 정수에 해당합니다 . 그러면 -2^63와 사이의 의미 있는 값을 얻게 됩니다 2^63-1. 그 범위를 넘어서면 서라운드를 얻을 수 있습니다.

답변3

1024를 이동하면 이동량이 실제로 비트 수(64)의 모듈로이므로 1이 1024 === 64 === 0됩니다 1025 === 65 === 1.

a 이외의 값을 이동하면 1이것이 비트 회전이 아님을 분명히 알 수 있습니다. 왜냐하면 이동 값이 (적어도) 64가 될 때까지 높은 비트가 낮은 비트로 순환되지 않기 때문입니다.

$ printf "%x\n" $(( 5 << 63 )) $(( 5 << 64 ))
8000000000000000
5

이 동작은 시스템에 따라 다를 수 있습니다. 이것bash 코드 Stephen이 링크됨오른쪽 값을 확인하지 않고 단순 시프트만 표시됩니다. 내 기억이 정확하다면 x86 프로세서는 시프트 값의 하위 6비트(64비트 모드)만 사용하므로 이 동작은 기계어에서 직접 나타날 수 있습니다. 또한 C에서는 비트 폭을 넘어서는 이동이 명확하게 정의되어 있지 않다고 생각합니다( gcc이 점에 대해 경고).

답변4

이동하여 정수를 생성합니다. 얼마나 멀리 갈 수 있나요?

최대 정수는 래핑을 나타냅니다(대부분의 쉘에서 기본값).
64비트 정수는 일반적으로 2**63 - 1.
그게 0x7fffffffffffffff아니면 922337203685477580712월이에요.

숫자 "+1"은 음수가 됩니다.

이는 와 동일하므로 다음과 같습니다 1<<63.

$ echo "$((1<<62)) $((1<<63)) and $((1<<64))"
4611686018427387904 -9223372036854775808 and 1

그 후 프로세스가 다시 반복됩니다.

$((1<<80000)) $((1<<1022)) $((1<<1023)) $((1<<1024)) $((1<<1025)) $((1<<1026))

결과는 mod 64이동 값 [a] 에 따라 달라집니다 .

[1] 보낸 사람:인텔® 64 및 IA-32 아키텍처 소프트웨어 개발자 핸드북: 볼륨 2개수는 5비트(또는 64비트 모드에서 REX.W를 사용하는 경우 6비트)로 마스크됩니다. 카운트 범위는 0~31(또는 64비트 모드를 사용하고 REX.W를 사용하는 경우 63)로 제한됩니다. .

또한: $((1<<0))그것이다는 것을 기억하십시오1

$ for i in 80000 1022 1023 1024 1025 1026; do echo "$((i%64)) $((1<<i))"; done
 0 1
62 4611686018427387904
63 -9223372036854775808
 0 1
 1 2
 2 4

따라서 그것은 모두 숫자가 64의 배수에 얼마나 가까운지에 달려 있습니다.

테스트 한계:

가장 큰 양수(및 음수) 정수를 테스트하는 신뢰할 수 있는 방법은 각 비트를 차례로 테스트하는 것입니다. 어쨌든 대부분의 컴퓨터에서는 64단계 미만이고 너무 느리지도 않습니다.

세게 때리다

먼저, 형식의 가장 큰 정수가 필요합니다 2^n(1비트 뒤에 0이 오는 집합). 우리는 왼쪽으로 이동하여 이를 수행할 수 있습니다.다음Shift를 사용하면 숫자가 음수가 됩니다("줄바꿈"이라고도 함).

a=1;   while ((a>0));  do ((b=a,a<<=1))  ; done

결과는 다음과 같습니다 b. 루프가 실패한 마지막 교대 이전의 값입니다.

그런 다음 각 비트를 시도하여 어느 것이 부호에 영향을 미치는지 알아내야 합니다 e.

c=$b;d=$b;
while ((c>>=1)); do
      ((e=d+c))
      (( e>0 )) && ((d=e))
done;
intmax=$d

가장 큰 정수( intmax)는 의 마지막 값에서 파생됩니다 d.

부정적인 측면(보다 작음 0)에서는 모든 테스트를 반복하지만, 비트를 래핑하지 않고 0으로 설정할 수 있을 때 테스트합니다.

모든 단계를 인쇄하는 전체 테스트는 다음과 같습니다(bash의 경우).

#!/bin/bash
sayit(){ printf '%020d 0x%016x\n' "$1"{,}; }
a=1;       while ((a>0)) ; do((b=a,a<<=1))              ; sayit "$a"; done
c=$b;d=$b; while((c>>=1)); do((e=d+c));((e>0))&&((d=e)) ; sayit "$d"; done;
intmax=$d
a=-1;      while ((a<0)) ; do((b=a,a<<=1))              ; sayit "$b"; done;
c=$b;d=$b; while ((c<-1)); do((c>>=1,e=d+c));((e<0))&&((d=e)); sayit "$d"; done
intmin=$d       

printf '%20d max positive value 0x%016x\n' "$intmax" "$intmax"
printf '%20d min negative value 0x%016x\n' "$intmin" "$intmin"

거의 모든 쉘로 변환됩니다.

#!/bin/sh
printing=false
sayit(){ "$printing" && printf '%020d 0x%016x\n' "$1" "$1"; }
a=1;       while [ "$a" -gt 0  ];do b=$a;a=$((a<<1)); sayit "$a"; done
c=$b;d=$b; while c=$((c>>1)); [ "$c" -gt 0 ];do e=$((d+c)); [ "$e" -gt 0 ] && d=$e ; sayit "$d"; done;
intmax=$d
a=-1;      while [ "$a" -lt 0  ];do b=$a;a=$((a<<1)); sayit "$b"; done;
c=$b;d=$b; while [ "$c" -lt -1 ];do c=$((c>>1));e=$((d+c));[ "$e" -lt 0 ] && d=$e ; sayit "$d"; done
intmin=$d       

printf '%20d max positive value 0x%016x\n' "$intmax" "$intmax"
printf '%20d min negative value 0x%016x\n' "$intmin" "$intmin"

많은 쉘에 대해 위 명령을 실행하면 모두(bash 2.04 및 mksh 제외)는 이 시스템에서
최대 ( ) 값을 허용합니다 .2**63 -1

흥미롭게도 보고서는 다음과 같이 말합니다.att 쉘:

$ attsh --version
version         sh (AT&T Research) 93u+ 2012-08-01

그러나 오류는 ksh가 아닌 ksh 값에 인쇄됩니다 $((2^63)).

관련 정보