32 비트 시스템은 명백한 32 비트 제한 때문에 2 ^ 33 숫자를 관리 할 수 없기 때문에 어떻게 80 비트 부동 소수점 숫자를 관리 할 수 있습니까?
"80 비트"가 필요합니다 ...
32 비트 시스템은 명백한 32 비트 제한 때문에 2 ^ 33 숫자를 관리 할 수 없기 때문에 어떻게 80 비트 부동 소수점 숫자를 관리 할 수 있습니까?
"80 비트"가 필요합니다 ...
답변:
32 비트 CPU의 의미 중 하나는 레지스터의 너비가 32 비트라는 것입니다. 이것은 64 비트 숫자를 처리 할 수 없다는 것을 의미하지 않으며, 먼저 하위 32 비트 반을 처리 한 다음 상위 32 비트 반 초를 처리해야합니다. (CPU에 캐리 플래그 가있는 이유 입니다.) CPU가 더 넓은 64 비트 레지스터에 값을로드 할 수있는 것보다 느리지 만 여전히 가능합니다.
따라서 시스템의 "비트 니스"는 프로그램이 처리 할 수있는 숫자의 크기를 반드시 제한하지는 않습니다. CPU 레지스터에 맞지 않는 연산을 여러 연산으로 항상 분할 할 수 있기 때문입니다. 따라서 작업 속도가 느려지고 더 많은 메모리를 사용하고 (메모리를 "스크래치 패드"로 사용해야하는 경우) 프로그래밍하기가 더 어렵지만 작업은 여전히 가능합니다.
그러나 CPU의 부동 소수점 부분에는 자체 레지스터가 있고 폭이 80 비트이므로 Intel 32 비트 프로세서 및 부동 소수점과 같은 것은 중요하지 않습니다. (초기 x86의 역사에서 부동 소수점 기능은 별도의 칩이었으며 80486DX부터 CPU에 통합되었습니다.)
@Breakthrough의 대답은 이것을 추가하도록 영감을주었습니다.
FPU 레지스터에 저장된 부동 소수점 값은 이진 정수 값과 매우 다른 방식으로 작동합니다.
부동 소수점 값의 80 비트는 가수와 지수로 나뉩니다 (항상 2 인 부동 소수점 숫자에 "기본"도 있습니다). 가수에는 유효 숫자가 포함되며 지수는 유효 숫자의 크기를 결정합니다. 따라서 다른 레지스터에 "오버플로"가 없습니다. 숫자가 가수에 비해 너무 커지면 지수가 증가하고 정밀도가 떨어집니다. 즉, 정수로 변환하면 소수점 이하 자릿수가 손실됩니다. 이것이 부동 소수점이라고하는 이유입니다.
지수가 너무 크면 부동 소수점 오버플로가 발생하지만 지수와 가수가 묶여 있기 때문에 다른 레지스터로 쉽게 확장 할 수 없습니다.
나는 그 중 일부에 대해 부정확하고 잘못 될 수 있지만 그것이 그 요점이라고 생각합니다. (이 Wikipedia 기사 는 위의 내용을 간결하게 보여줍니다.)
CPU의 전체 "부동 소수점"부분은 자체 세계에 있으므로 완전히 다르게 작동하는 것이 좋습니다. 특수 CPU 명령어를 사용하여 액세스하는 등의 작업이 가능합니다. 또한, 문제의 시점을 향해서, 그것은 별도이기 때문에 FPU의 비트는 기본 CPU의 비트와 밀접하게 결합되지 않습니다.
-fomit-frame-pointer
하면 해당 레지스터를 다시 가져올 수 있습니다 .
32 비트, 64 비트 및 128 비트는 모두 "기본 데이터 유형"으로 간주 될 수있는 프로세서 의 워드 길이 를 나타냅니다. 종종 이것은 시스템의 RAM으로 /로부터 전송되는 비트 수와 포인터의 너비입니다 (단 하나의 포인터가 액세스 할 수있는 것보다 더 많은 RAM에 액세스하기 위해 소프트웨어를 사용하는 것을 막을 수는 없지만).
일정한 클럭 속도 (아키텍처의 다른 모든 것이 일정 함)를 가정하고 메모리 읽기 / 쓰기가 동일한 속도라고 가정하면 (여기서는 1 클럭 사이클을 가정하지만 실제로는 그렇지 않습니다) 64 비트 컴퓨터에서 단일 클록 주기로 2 개의 64 비트 숫자를 추가합니다 (RAM에서 숫자를 가져 오는 경우 세 개).
ADDA [NUM1], [NUM2]
STAA [RESULT]
32 비트 시스템 에서도 동일한 계산을 수행 할 수 있습니다 . 그러나 32 비트 시스템에서는 하위 32 비트를 먼저 추가하고 오버 플로우를 보상 한 다음 추가해야하므로 소프트웨어에서이를 수행해야합니다. 상위 64 비트 :
ADDA [NUM1_LOWER], [NUM2_LOWER]
STAA [RESULT_LOWER]
CLRA ; I'm assuming the condition flags are not modified by this.
BRNO CMPS ; Branch to CMPS if there was no overflow.
ADDA #1 ; If there was overflow, compensate the value of A.
CMPS ADDA [NUM1_UPPER], [NUM2_UPPER]
STAA [RESULT_UPPER]
내가 만든 어셈블리 구문을 통해 더 짧은 워드 길이 머신에서 고정밀 연산이 어떻게 기하 급수적으로 더 오래 걸릴 수 있는지 쉽게 알 수 있습니다. 이것이 64 비트 및 128 비트 프로세서의 핵심 요소입니다. 단일 작업에서 더 많은 수의 비트를 처리 할 수 있습니다. 일부 기계에는 캐리 (예 : ADC
x86) 와 함께 다른 수량을 추가하기위한 지침이 포함되어 있지만 위의 예는 임의의 정밀도 값을 염두에두고 있습니다.
이제 이것을 질문으로 확장하기 위해 사용 가능한 레지스터보다 큰 숫자를 추가하는 방법을 간단하게 알 수 있습니다. 문제를 레지스터 크기의 덩어리로 나누고 거기서부터 작업합니다. @MatteoItalia 에서 언급했듯이 x87 FPU 스택은 80 비트 수량을 기본적으로 지원하지만이 지원이없는 시스템 (또는 부동 소수점 단위가 완전히없는 프로세서)에서는 동등한 계산 / 작동 이 소프트웨어에서 수행되어야합니다 .
따라서 80 비트 숫자의 경우 각 32 비트 세그먼트를 추가 한 후 81 번째 비트로 오버플로를 확인하고 선택적으로 상위 비트를 0으로 만듭니다. 소스 및 대상 피연산자 크기가 지정되어있는 특정 x86 및 x86-64 명령어에 대해 이러한 검사 / 0이 자동으로 수행됩니다 (1 바이트 폭부터 2의 거듭 제곱에만 지정되지만).
물론 부동 소수점 숫자의 경우 가수와 유효 숫자가 오프셋 형식으로 묶여 있기 때문에 이진 덧셈을 수행 할 수 없습니다. x86 프로세서의 ALU에는 IEEE 32 비트 및 64 비트 플로트에이를 수행하기위한 하드웨어 회로가 있습니다. 그러나 FPU (부동 소수점 단위)가없는 경우에도 소프트웨어에서 동일한 계산을 수행 할 수 있습니다 (예 : GNU Scientific Library 를 사용하여 아키텍처에서 컴파일 할 때 FPU를 사용하여 소프트웨어 알고리즘으로 폴 백함). 부동 소수점 하드웨어를 사용할 수없는 경우 (예 : FPU가없는 임베디드 마이크로 컨트롤러의 경우).
충분한 메모리가 주어지면, 더 많은 정밀도가 필요할수록 더 많은 메모리를 사용하여 임의의 (또는 실제 범위 내에서 "무한"정밀도) 정밀도로 계산을 수행 할 수 있습니다 . 이것의 한가지 구현은 GNU Multiple Precision 라이브러리에 존재하며, 정수, 합리적, 부동 소수점 연산에서 (정확히 RAM이 가득 찰 때까지) 무제한 정밀도를 허용합니다.
시스템의 메모리 아키텍처는 한 번에 32 비트 만 이동할 수 있지만 더 큰 숫자를 사용하는 것을 막지는 않습니다.
곱셈을 생각하십시오. 곱셈 테이블을 최대 10x10까지 알 수 있지만 한 장의 종이에서 123x321을 수행하는 데 아무런 문제가 없습니다. 테이블을 여러 작은 문제로 나누고 개별 숫자를 곱하고 캐리 등을 돌보는 것입니다.
프로세서도 같은 작업을 수행 할 수 있습니다. "오래된 시대"에는 부동 소수점 연산을 수행 할 수있는 8 비트 프로세서가있었습니다. 그러나 그들은 어리 석었습니다.
"32 비트"는 실제로 일련의 판결이 아니라 프로세서를 분류하는 방법입니다. "32 비트"프로세서에는 일반적으로 32 비트 범용 레지스터가 있습니다.
그러나 프로세서의 모든 내용을 32 비트로 수행해야하는 요구 사항은 없습니다. 예를 들어 "32 비트"컴퓨터에 28 비트 주소 버스가있는 것은 들어 보지 못했습니다. 하드웨어를 만드는 것이 더 저렴했기 때문입니다. 64 비트 컴퓨터에는 종종 같은 이유로 40 비트 또는 48 비트 메모리 버스 만 있습니다.
부동 소수점 산술은 크기가 다른 또 다른 장소입니다. 많은 32 비트 프로세서가 64 비트 부동 소수점 숫자를 지원했습니다. 부동 소수점 값을 범용 레지스터보다 넓은 특수 레지스터에 저장하여이를 수행했습니다. 이러한 큰 부동 소수점 숫자 중 하나를 특수 레지스터에 저장하려면 먼저 두 개의 범용 레지스터에서 숫자를 분할 한 다음 특수 레지스터에서 부동 소수점으로 결합하는 명령을 발행합니다. 일단 부동 소수점 레지스터에서 값은 한 쌍의 32 비트 반이 아닌 64 비트 부동 소수점으로 조작됩니다.
언급 한 80 비트 산술은 특별한 경우입니다. 부동 소수점 숫자로 작업 한 경우 부동 소수점 반올림 문제에서 발생하는 부정확성에 익숙합니다. 반올림에 대한 한 가지 해결책은 더 많은 정밀도를 갖는 것이지만 더 큰 수를 저장해야하며 개발자가 메모리에 비정상적으로 큰 부동 소수점 값을 사용하도록해야합니다.
인텔 솔루션은 부동 소수점 레지스터가 모두 80 비트이지만 레지스터에서 값을 이동하는 명령은 64 비트 숫자로 기본적으로 작동합니다. Intel의 x87 부동 소수점 스택 내에서 완전히 작동하는 한 모든 작업은 80 비트 정밀도로 수행됩니다. 코드가 부동 소수점 레지스터에서 해당 값 중 하나를 가져와 어딘가에 저장해야하는 경우 64 비트로 잘립니다.
이야기의 교훈 : "32 비트"와 같은 분류는 더 깊이 들어가면 항상 더 위험합니다!
"32 비트"CPU는 대부분의 데이터 레지스터가 32 비트 레지스터이고 대부분의 명령어는 해당 32 비트 레지스터의 데이터에서 작동합니다. 32 비트 CPU는 한 번에 메모리 32 비트와 데이터를주고받을 수도 있습니다. 32 비트 인 대부분의 레지스터가 모든 레지스터가 32 비트 인 것은 아닙니다. 짧은 대답은 32 비트 CPU가 80 비트 부동 소수점 레지스터 및 해당 명령어와 같은 다른 비트 수를 사용하는 일부 기능을 가질 수 있다는 것입니다.
@spudone이 @ultrasawblade의 답변에 대한 의견에서 언급했듯이, 부동 소수점 연산을 통합 한 최초의 x86 CPU는 Intel i486 (특히 80486DX는 아니지만 80486SX는 아님)으로, i486 마이크로 프로세서 프로그래머의 15-1 페이지 에 따르면 Reference Manual 은 숫자 레지스터에 개별적으로 주소를 지정할 수있는 80 비트 숫자 레지스터 8 개를 포함합니다. i486에는 32 비트 메모리 버스가 있으므로 80 비트 값을 전송하면 3 번의 메모리 작업이 필요합니다.
486 세대의 전임자 인 i386에는 통합 부동 소수점 연산이 없었습니다. 대신, 외부 부동 소수점 "코 프로세서"(80387) 사용을 지원했습니다.이 코 프로세서는 80387 프로그래머 참조 서의 2-1 페이지에서 볼 수 있듯이 i486에 통합 된 기능과 거의 동일한 기능을 가졌습니다 .
80 비트 부동 소수점 형식은 8086 및 8088의 수학 보조 프로세서 인 8087에서 시작된 것으로 보입니다. 8086 및 8088은 16 비트 CPU (16 비트 및 8 비트 메모리 버스 포함)였으며 여전히 가능했습니다. 보조 프로세서에서 80 비트 레지스터를 이용하여 80 비트 부동 소수점 형식을 사용합니다.