마이크로 프로세서 시스템이 부호없는 숫자를 구현하는 이유를 알 수 없습니다. 나는 비용이 조건 분기의 수의 두 배라고 생각합니다.보다 크거나 작습니다.
내 질문은 부분적으로 컴파일러에서 지원하는 대신 명령어 세트에 있어야하는 이유입니다.
마이크로 프로세서 시스템이 부호없는 숫자를 구현하는 이유를 알 수 없습니다. 나는 비용이 조건 분기의 수의 두 배라고 생각합니다.보다 크거나 작습니다.
내 질문은 부분적으로 컴파일러에서 지원하는 대신 명령어 세트에 있어야하는 이유입니다.
답변:
부호없는 숫자는 일련의 비트를 해석하는 것입니다. 또한 주소 및 op 코드가 비트이기 때문에 CPU 내부에서 가장 단순하고 가장 많이 사용되는 해석입니다. 메모리 / 스택 어드레싱 및 산술은 마이크로 프로세서의 기본입니다. 추상화 피라미드 위로 올라가면 비트에 대한 또 다른 빈번한 해석은 문자 (ASCII, Unicode, EBCDIC)입니다. 그런 다음 IEEE 부동 소수점, 그래픽 용 RGBA 등과 같은 다른 해석이 있습니다. 이들 중 어느 것도 단순한 부호가있는 숫자가 아닙니다 (IEEE FP는 단순하지 않으며,이를 사용하는 산술은 매우 복잡합니다).
또한 부호없는 산술을 사용하면 다른 것을 구현하는 것이 매우 간단합니다 (가장 효율적이지 않은 경우). 대화는 사실이 아닙니다.
비교 작업을위한 하드웨어 비용의 대부분은 빼기입니다. 비교에 사용 된 빼기의 출력은 기본적으로 3 비트 상태입니다.
빼기 연산 후에이 세 비트를 테스트하는 적절한 조합을 사용하면 모든 부호없는 관계 연산뿐만 아니라 모든 부호없는 관계 연산을 확인할 수 있습니다 (이 비트는 오버플로가 감지되는 방식, 부호있는 방식 대 부호없는 방식). 동일한 기본 ALU 하드웨어를 공유하여 원하는 관계 비교에 따라 다른 3 비트 상태를 최종 확인할 때까지 이러한 모든 비교 (빼기 명령은 말할 것도없고)를 구현할 수 있습니다. 따라서 많은 추가 하드웨어가 아닙니다.
유일한 실제 비용은 명령어 세트 아키텍처에서 추가적인 비교 모드를 인코딩 할 필요가 있으며, 이는 명령어 밀도를 약간 감소시킬 수있다. 그러나 하드웨어에 주어진 언어에서 사용되지 않는 많은 명령이있는 것은 일반적입니다.
항상 >= 0
인 것을 계산 해야하는 경우 부호있는 정수를 사용하여 불필요하게 계산 공간을 반으로 줄입니다.
데이터베이스 테이블에 넣을 수있는 자동 증분 INT PK를 고려하십시오. 당신이 사용하는 경우가 많은 레코드가 등으로,이 테이블 저장 HALF를 정수에 서명 할 수 없음 혜택과 같은 필드 크기.
또는 RGBa 색상의 옥텟. 우리는 자연스럽게 양수 개념을 음수로 세는 것을 어색하게 시작하고 싶지 않습니다. 서명 된 숫자는 정신 모델을 깨뜨 리거나 공간을 반으로 줄입니다. 부호없는 정수는 개념과 일치 할뿐만 아니라 해상도의 두 배를 제공합니다.
하드웨어 관점에서 부호없는 정수는 간단합니다. 아마도 수학을 수행하기에 가장 쉬운 비트 구조 일 것입니다. 그리고 의심 할 여지없이 컴파일러에서 정수 유형 (또는 부동 소수점!)을 시뮬레이션하여 하드웨어를 단순화 할 수 있습니다. 그렇다면 왜 부호없는 정수 와 부호있는 정수가 하드웨어 에서 구현 됩니까?
음 ... 성능!
부호있는 정수를 소프트웨어보다 하드웨어에서 구현하는 것이 더 효율적입니다. 하드웨어는 단일 명령으로 정수 유형에 대해 수학을 수행하도록 지시 할 수 있습니다. 그리고 그건 아주 좋은 하드웨어가 함께 비트를 부수고 있기 때문에, 더 많거나 적은 병렬. 소프트웨어에서이를 시뮬레이션하려고하면 "시뮬레이션"하도록 선택한 정수 유형은 의심 할 여지없이 많은 명령을 필요로 하며 눈에 띄게 느려집니다.
귀하의 질문은 두 부분으로 구성됩니다.
부호없는 정수의 목적은 무엇입니까?
부호없는 정수가 문제의 가치가 있습니까?
부호없는 숫자는 간단히 말해서 음수 값이 의미가없는 양의 클래스를 나타냅니다. 물론, 당신은 "내가 얼마나 많은 사과를 가지고 있습니까?"라는 질문에 대한 답을 말할 수 있습니다. 사과를 누군가에게 빚진다면 음수가 될 수 있지만 "메모리 용량이 얼마나됩니까?"라는 질문은 어떻습니까? -음수의 메모리를 가질 수 없습니다. 따라서 부호없는 정수는 그러한 양을 나타내는 데 매우 적합하며 부호있는 정수보다 양수 범위의 두 배를 나타낼 수 있다는 이점이 있습니다. 예를 들어 16 비트 부호있는 정수로 나타낼 수있는 최대 값은 32767이고 16 비트 부호없는 정수는 65535입니다.
부호없는 정수는 실제로 문제를 나타내지 않으므로 그만한 가치가 있습니다. 알다시피, 그들은 추가적인 "알고리즘"을 필요로하지 않습니다. 그것들을 구현하는 데 필요한 회로는 부호있는 정수를 구현하는 데 필요한 회로의 하위 집합입니다.
CPU에는 부호있는 정수에 대한 승수 하나와 부호없는 정수에 대한 승수가 없습니다. 승수는 하나 뿐이며 연산의 특성에 따라 약간 다른 방식으로 작동합니다. 부호있는 곱셈을 지원하려면 부호없는 것보다 약간 더 많은 회로가 필요하지만 어쨌든 지원해야하므로 부호없는 곱셈은 실제로 무료로 제공되므로 패키지에 포함됩니다.
덧셈과 뺄셈은 회로에 전혀 차이가 없습니다. 정수의 소위 2의 보수 표현 을 읽으면 정수 의 특성에 관계 없이이 연산이 정확히 동일한 방식으로 수행 될 수 있도록 영리하게 설계되었음을 알 수 있습니다.
비교도 같은 방식으로 작동합니다. 결과를 빼고 무시하는 것 외에는 유일한 차이점은 조건부 분기 (점프) 명령에 있습니다.이 명령은 조건부 분기 (점프) 명령에 있습니다. 선행 (비교) 명령. 이 답변에서 /programming//a/9617990/773113 인텔 x86 아키텍처에서 어떻게 작동하는지에 대한 설명을 찾을 수 있습니다. 발생하는 조건은 조건부 점프 명령을 부호있는 또는 부호없는 것으로 지정하는 것은 검사하는 플래그에 따라 다릅니다.
마이크로 프로세서는 본질적으로 부호가 없습니다. 부호있는 숫자는 다른 방식이 아니라 구현 된 것입니다.
컴퓨터는 부호있는 숫자 없이도 잘 작동 할 수 있습니다. 그러나 음수를 필요로하는 인간 인 우리는 부호가 발명되었습니다.
저장에 쉽게 사용할 수있는 비트가 하나 더 있으므로 음수에 대해 걱정할 필요가 없습니다. 그것보다 더 많은 것이 없습니다.
이 여분의 비트 가 필요한 곳의 예가 필요 하다면 살펴보면 충분히 찾을 수 있습니다.
가장 좋아하는 예는 체스 엔진의 비트 보드에서 비롯됩니다. 체스 판에는 64 개의 정사각형이 있으므로 unsigned long
이동 생성을 중심으로 회전하는 다양한 알고리즘을위한 완벽한 스토리지를 제공합니다. 바이너리 연산 (및 시프트 연산 !!)이 필요하다는 사실을 고려하면 MSB가 설정되면 어떤 특수한 일이 발생하는지 걱정하지 않아도되는 이유를 쉽게 알 수 있습니다. 부호가있는 long으로 수행 할 수 있지만 부호없는 것을 사용 하는 것이 훨씬 쉽습니다.
순수한 수학 배경을 가진 사람은 관심있는 사람이 조금 더 수학적으로 이해해야합니다.
8 비트 부호있는 정수와 부호없는 정수로 시작한다면, 우리가 가진 것은 기본적으로 정수 모듈로 256입니다. 더하기와 곱셈에 관해서는 2의 보수가 음의 정수를 나타내는 데 사용된다면 (모든 현대 프로세서가 그것을 수행하는 방식입니다) .
상황이 다른 곳은 두 곳이 있습니다. 하나는 비교 연산입니다. 어떤 의미에서, 정수 모듈로 (256)는 숫자의 원으로 가장 잘 고려된다 (정수 모듈로 (12)는 구식 아날로그 문자판에서 수행하는 것처럼). 숫자 비교 (x <y)를 의미있게하기 위해 어떤 숫자가 다른 숫자보다 적은지를 결정해야했습니다. 수학자의 관점에서, 우리는 정수 modulo 256을 모든 정수 세트에 포함시키기를 원합니다. 이진 표현이 모두 0 인 8 비트 정수를 정수 0에 매핑하는 것이 분명합니다. 그런 다음 '0 + 1'(레지스터 제로화, ax라고 말하고 'inc ax'를 통해 1 씩 증분 한 결과)이 정수 1이되도록 다른 맵을 계속 진행할 수 있습니다. 예를 들어 '0-1'을 정수 -1에 매핑하고 '0-1-1'을 매핑하는 것과 같이 -1과 동일한 작업을 수행 할 수 있습니다. 정수 -2로 이 임베딩이 함수인지 확인해야하므로 단일 8 비트 정수를 두 정수로 맵핑 할 수 없습니다. 따라서 모든 숫자를 정수 세트에 매핑하면 0보다 작은 정수와 0보다 큰 정수와 함께 0이 있습니다. 8 비트 정수 로이 작업을 수행하는 본질적으로 255 가지 방법이 있습니다 ( 0에서 -255까지) 그런 다음 '0 <y-x'로 'x <y'를 정의 할 수 있습니다.
하드웨어 지원이 합리적인 두 가지 일반적인 사용 사례가 있습니다. 하나는 0이 아닌 정수가 모두 0보다 크며 다른 하나는 0을 기준으로 약 50/50으로 나뉩니다. 다른 모든 가능성은 추가 '추가를 통해 숫자를 변환하여 쉽게 에뮬레이션합니다. 그리고 sub '를 작업하기 전에, 이것에 대한 필요성은 현대 소프트웨어의 명시 적 예를 생각할 수없는 것보다 드물다 (16 비트와 같은 더 큰 가수로 작업 할 수 있기 때문에).
다른 문제는 8 비트 정수를 16 비트 정수의 공간에 매핑하는 것입니다. -1이 -1로 이동합니까? 0xFF가 -1을 나타내는 경우에 원하는 것입니다. 이 경우 부호 확장은 현명한 일이므로 0xFF는 0xFFFF로 이동합니다. 반면에 0xFF가 255를 나타내려면 0xFFFF가 아니라 255에 매핑되므로 0x00FF로 매핑됩니다.
이것은 'shift'와 'arithmetic shift'연산의 차이점입니다.
그러나 궁극적으로 소프트웨어의 int는 정수가 아니라 이진 표현이며 일부만 표현할 수 있다는 사실에 달려 있습니다. 하드웨어를 설계 할 때 하드웨어에서 기본적으로 수행 할 작업을 선택해야합니다. 2의 보수로 덧셈과 곱셈 연산이 동일하기 때문에 이런 식으로 음의 정수를 나타내는 것이 좋습니다. 그런 다음 이진 표현이 나타내는 정수에 의존하는 작업의 문제 일뿐입니다.
부호없는 정수를 기존 부호있는 정수로 CPU 디자인에 추가하기위한 구현 비용을 조사 할 수 있습니다.
일반적인 CPU에는 다음과 같은 산술 명령어가 필요합니다.
논리적 인 지침도 필요합니다 :
부호있는 정수 비교에서 위의 분기를 수행하려면 가장 쉬운 방법은 SUB 명령이 다음 플래그를 설정하는 것입니다.
그런 다음 산술 분기는 다음과 같이 구현됩니다.
이것들의 부정은 그것들이 어떻게 구현되는지 분명하게 따라야합니다.
따라서 기존 디자인은 이미 부호있는 정수에 대해 이들을 모두 구현합니다. 이제 부호없는 정수를 추가하기 위해해야 할 일을 고려하십시오.
각각의 경우에, 수정은 매우 간단하고 , 작은 회로 부분을 온 또는 오프로 게이팅하거나, 또는 새로운 플래그 레지스터를 추가함으로써 간단하게 구현 될 수 있음을 주목해야한다. 어쨌든 명령의 구현.
따라서 서명되지 않은 명령어를 추가하는 비용은 매우 적습니다 . 이 이유에 수행해야합니다 (배열의 오프셋 (offset)) 그 메모리 주소는 본래 부호없는 값입니다 유의하십시오. 프로그램이 메모리 주소를 조작하는 데 많은 시간을 소비하므로 올바르게 처리하는 유형이 있으면 프로그램을보다 쉽게 작성할 수 있습니다.
부호없는 숫자는 래핑 대수 고리가 필요한 상황을 처리하기 위해 주로 존재합니다 (16 비트 부호없는 유형의 경우 정수의 고리가 일치하는 모드 65536). 값을 취하고 계수보다 적은 양을 추가하면 두 값의 차이가 추가 된 양이됩니다. 실제 예를 들어, 월초에 유틸리티 미터가 9995를 읽고 23 개를 사용하는 경우 미터는 월말에 0018을 읽습니다. 대수 링 유형을 사용하는 경우 오버플로를 처리하기 위해 특별한 작업을 수행 할 필요가 없습니다. 0018에서 9995를 빼면 정확히 사용한 단위 수인 0023이 생성됩니다.
C가 처음 구현 된 PDP-11에는 부호없는 정수 유형이 없었지만 부호있는 유형은 65535와 0이 아닌 32767과 -32768 사이에 랩핑 된 모듈 식 산술에 사용될 수 있습니다. 그러나 플랫폼은 물건을 깨끗하게 포장하지 않았습니다. 오히려 구현이 PDP-11에서 사용되는 보수 정수 대신 부호없는 유형의 추가 언어 모방해야한다는 요구보다는 주로 대수 반지처럼 행동했고, 오버 플로우의 경우 다른 방식으로 행동하는 유형의 정수 서명 허용합니다.
C 초기에는 32767 (공통 INT_MAX)을 초과 할 수 있지만 65535 (공통 UINT_MAX)를 초과 할 수없는 수량이 많았습니다. 따라서 부호없는 유형을 사용하여 그러한 수량을 보유하는 것이 일반적이되었습니다 (예 : size_t). 불행히도, 언어에는 양의 범위의 여분 비트를 가진 숫자처럼 행동해야하는 유형과 대수 고리처럼 행동해야하는 유형을 구별 할 수있는 것이 없습니다. 대신, 언어는 "int"보다 작은 유형은 숫자처럼 동작하고 전체 크기 유형은 대수 고리처럼 동작합니다. 결과적으로 다음과 같은 함수를 호출합니다.
uint32_t mul(uint16_t a, uint16_t b) { return a*b; }
(65535, 65535)를 사용하면 int
16 비트 (즉, 리턴 1) 인 시스템에서 하나의 정의 된 동작 , int
33 비트 이상 (0xFFFE0001 리턴) 인 다른 동작 및 "int"가있는 시스템의 경우 정의되지 않은 동작이 있습니다. [gcc는 보통 INT_MAX + 1u와 UINT_MAX 사이의 결과로 산술적으로 올바른 결과를 산출하지만, 때때로 그러한 값으로 실패하는 위 함수에 대한 코드를 생성합니다!]. 별로 도움이되지 않습니다.
그럼에도 불구하고, 숫자처럼 일관되게 또는 대수 고리처럼 일관되게 작동하는 유형이 없다고해서 어떤 종류의 프로그래밍에 대수 고리 유형이 거의 없어야한다는 사실은 변하지 않습니다.