부호없는 숫자가 구현되는 이유는 무엇입니까?


12

마이크로 프로세서 시스템이 부호없는 숫자를 구현하는 이유를 알 수 없습니다. 나는 비용이 조건 분기의 수의 두 배라고 생각합니다.보다 크거나 작습니다.

내 질문은 부분적으로 컴파일러에서 지원하는 대신 명령어 세트에 있어야하는 이유입니다.


27
기본적으로 부호없는 숫자는 표준이며 부호있는 숫자는 음수를 제공하기 위해 구현됩니다.
Pieter B

37
세계의 많은 데이터는 숫자가 아닙니다. 숫자가 아닌 데이터는 부호없는 유형을 사용하여 쉽게 조작 할 수 있습니다. Java에 부호없는 숫자 유형이 없다는 것은 실패이므로 숫자가 아닌 데이터를 조작 해야하는 많은 버그 (예 : 압축 등)가 발생합니다.
Erik Eidt

6
@jtw Erik은 음의 픽셀 색상이나 음의 문자는 없다고 말합니다. 따라서 부호있는 정수를 사용하는 것은 낭비이며 주소 공간의 절반을 포기합니다.
Martin Maat

26
나는 여기 혼자 있는지 확실하지 않지만 응용 프로그램을 개발할 때 부호있는 정수 가 필요하다는 것은 놀랍지 않습니다. 필자가 필요로하는 거의 모든 시간은 (부호없는) 자연수 (양수 크기) 또는 부호있는 부동 소수점 숫자입니다. 예외는 통화와 같지만 매우 드 rare니다. 나에게 부호없는 정수는 표준이며 부호있는 정수는 예외입니다!
토마스

11
CPU의 관점에서 보면 거의 모든 숫자가 부호가 없습니다. 몇 가지 명령어는 비트를 부호있는 것으로 해석 할 수 있지만 (예 : 산술-오른쪽 시프트) 실제로 2의 보수 는 CPU가 부호있는 정수를 부호없는 정수로 취급 할 수있게합니다. .
Cornstalks

답변:


39

부호없는 숫자는 일련의 비트를 해석하는 것입니다. 또한 주소 및 op 코드가 비트이기 때문에 CPU 내부에서 가장 단순하고 가장 많이 사용되는 해석입니다. 메모리 / 스택 어드레싱 및 산술은 마이크로 프로세서의 기본입니다. 추상화 피라미드 위로 올라가면 비트에 대한 또 다른 빈번한 해석은 문자 (ASCII, Unicode, EBCDIC)입니다. 그런 다음 IEEE 부동 소수점, 그래픽 용 RGBA 등과 같은 다른 해석이 있습니다. 이들 중 어느 것도 단순한 부호가있는 숫자가 아닙니다 (IEEE FP는 단순하지 않으며,이를 사용하는 산술은 매우 복잡합니다).

또한 부호없는 산술을 사용하면 다른 것을 구현하는 것이 매우 간단합니다 (가장 효율적이지 않은 경우). 대화는 사실이 아닙니다.


3
EBCDIC에는 "I"가 하나만 있습니다.
Ruslan

4
@Ruslan-그러나 두 개가있는 것처럼 발음 됩니다. <g>
피트 베커

5
@PeteBecker 아니오 그렇지 않습니다. EBCDIC는 eb -see-dick으로 발음 됩니다.
Mike Nakis

19

비교 작업을위한 하드웨어 비용의 대부분은 빼기입니다. 비교에 사용 된 빼기의 출력은 기본적으로 3 비트 상태입니다.

  • 모든 비트가 0인지 (즉, 동일한 조건)
  • 결과의 부호 비트
  • 빼기의 캐리 비트 (예 : 32 비트 컴퓨터의 33 번째 상위 비트)

빼기 연산 후에이 세 비트를 테스트하는 적절한 조합을 사용하면 모든 부호없는 관계 연산뿐만 아니라 모든 부호없는 관계 연산을 확인할 수 있습니다 (이 비트는 오버플로가 감지되는 방식, 부호있는 방식 대 부호없는 방식). 동일한 기본 ALU 하드웨어를 공유하여 원하는 관계 비교에 따라 다른 3 비트 상태를 최종 확인할 때까지 이러한 모든 비교 (빼기 명령은 말할 것도없고)를 구현할 수 있습니다. 따라서 많은 추가 하드웨어가 아닙니다.

유일한 실제 비용은 명령어 세트 아키텍처에서 추가적인 비교 모드를 인코딩 할 필요가 있으며, 이는 명령어 밀도를 약간 감소시킬 수있다. 그러나 하드웨어에 주어진 언어에서 사용되지 않는 많은 명령이있는 것은 일반적입니다.


1
부호없는 숫자의 비교는 빼기를 요구하지 않습니다. 왼쪽에서 오른쪽으로 비트 비교를 통해 얻을 수 있습니다.
Jonathan Rosenne

10
@JonathanRosenne 그러나 프로세서가 그것을 구현하는 방법은 아닙니다. 반대로 2의 보수 프로세서가 ALU에서 (캐리 / 빌리가 있거나없는) 빼기를 구현하지 않는 것은 거의 생각할 수 없습니다. 디자이너의 즉각적인 생각은이 필요한 ALU를 사용하여 같은 돌로 다른 새를 죽이는 것입니다. 그런 다음 비교는 단순히 결과를 레지스터 파일에 다시 쓰지 않는 빼기가됩니다.
Idonotexist Idonotexist

4
+1 : 이것은 질문에 대한 정답입니다. 요약 : 서명되지 않은 작업을 구현하는 거의 무료이기 때문에 당신이 이미 서명하여 구현 한 경우 .
Periata Breatta

10
@PeriataBreatta 또한 다른 방법으로 작동합니다. 최신 CPU의 부호있는 숫자와 부호없는 숫자는 거의 동일하며 이는 OP가 인식하지 못한 주요 지점입니다. 비교 명령조차도 부호가
있거나

3
@svidgen> 다른 답변에서 알 수 있듯이 다른 방식으로 작동합니다. 주요 관심사는 부호없는 숫자로, 기본적으로 모든 것 (메모리 주소, IO / 포트, 문자 표현 등)에 사용됩니다. 부호가없는 숫자는 부호가 없으면 저렴하고, 드문 경우에 유용합니다.
스펙트럼

14

항상 >= 0 인 것을 계산 해야하는 경우 부호있는 정수를 사용하여 불필요하게 계산 공간을 반으로 줄입니다.

데이터베이스 테이블에 넣을 수있는 자동 증분 INT PK를 고려하십시오. 당신이 사용하는 경우가 많은 레코드가 등으로,이 테이블 저장 HALF를 정수에 서명 할 수 없음 혜택과 같은 필드 크기.

또는 RGBa 색상의 옥텟. 우리는 자연스럽게 양수 개념을 음수로 세는 것을 어색하게 시작하고 싶지 않습니다. 서명 된 숫자는 정신 모델을 깨뜨 리거나 공간을 반으로 줄입니다. 부호없는 정수는 개념과 일치 할뿐만 아니라 해상도의 두 배를 제공합니다.

하드웨어 관점에서 부호없는 정수는 간단합니다. 아마도 수학을 수행하기에 가장 쉬운 비트 구조 일 것입니다. 그리고 의심 할 여지없이 컴파일러에서 정수 유형 (또는 부동 소수점!)을 시뮬레이션하여 하드웨어를 단순화 할 수 있습니다. 그렇다면 왜 부호없는 정수 부호있는 정수가 하드웨어 에서 구현 됩니까?

음 ... 성능!

부호있는 정수를 소프트웨어보다 하드웨어에서 구현하는 것이 더 효율적입니다. 하드웨어는 단일 명령으로 정수 유형에 대해 수학을 수행하도록 지시 할 수 있습니다. 그리고 그건 아주 좋은 하드웨어가 함께 비트를 부수고 있기 때문에, 더 많거나 적은 병렬. 소프트웨어에서이를 시뮬레이션하려고하면 "시뮬레이션"하도록 선택한 정수 유형은 의심 할 여지없이 많은 명령을 필요로 하며 눈에 띄게 느려집니다.


2
이러한 행을 따라 배열 범위 검사를 수행 할 때 작업을 절약 할 수 있습니다. 부호없는 정수를 사용하는 경우 제공된 인덱스가 배열 크기보다 작은 지 확인하면됩니다 (음수가 될 수 없으므로).
riwalk

2
@ dan04 확실히 할 수 있습니다. 그러나 0 또는 1에서 시작하는 자동 증가 int를 사용하는 경우가 일반적입니다. 사용 가능한 숫자의 절반을 사용할 수 없습니다. 그리고 아마도 -2 ^ 31 (또는 무엇이든)에서 카운팅을 시작할 수는 있지만 id 공간의 중간에 잠재적 인 "가장자리"가있을 것입니다.
svidgen

1
필드를 반으로 자르는 것은 일종의 약한 논쟁입니다. 앱에 20 억 이상이 필요하고 40 억 이상이 필요할 수도 있습니다.
corsiKa

1
@corsiKa : 그 때문에 4를 초과하면 8, 16 등이 필요할 것입니다. 어디에서 끝나는가?
whatsisname

1
@whatsisname 일반적으로 정수 유형은 8, 16, 32 또는 64 비트를 사용합니다. 부호없는 바이트에서 양의 정수 공간 31 비트의 제한된 범위 대신 32 비트를 모두 얻으므로 부호없는 것이 더 좋습니다 . 대부분의 경우 중요하지 않습니다.
corsiKa

9

귀하의 질문은 두 부분으로 구성됩니다.

  1. 부호없는 정수의 목적은 무엇입니까?

  2. 부호없는 정수가 문제의 가치가 있습니까?

1. 부호없는 정수의 목적은 무엇입니까?

부호없는 숫자는 간단히 말해서 음수 값이 의미가없는 양의 클래스를 나타냅니다. 물론, 당신은 "내가 얼마나 많은 사과를 가지고 있습니까?"라는 질문에 대한 답을 말할 수 있습니다. 사과를 누군가에게 빚진다면 음수가 될 수 있지만 "메모리 용량이 얼마나됩니까?"라는 질문은 어떻습니까? -음수의 메모리를 가질 수 없습니다. 따라서 부호없는 정수는 그러한 양을 나타내는 데 매우 적합하며 부호있는 정수보다 양수 범위의 두 배를 나타낼 수 있다는 이점이 있습니다. 예를 들어 16 비트 부호있는 정수로 나타낼 수있는 최대 값은 32767이고 16 비트 부호없는 정수는 65535입니다.

2. 부호없는 정수가 문제의 가치가 있습니까?

부호없는 정수는 실제로 문제를 나타내지 않으므로 그만한 가치가 있습니다. 알다시피, 그들은 추가적인 "알고리즘"을 필요로하지 않습니다. 그것들을 구현하는 데 필요한 회로는 부호있는 정수를 구현하는 데 필요한 회로의 하위 집합입니다.

CPU에는 부호있는 정수에 대한 승수 하나와 부호없는 정수에 대한 승수가 없습니다. 승수는 하나 뿐이며 연산의 특성에 따라 약간 다른 방식으로 작동합니다. 부호있는 곱셈을 지원하려면 부호없는 것보다 약간 더 많은 회로가 필요하지만 어쨌든 지원해야하므로 부호없는 곱셈은 실제로 무료로 제공되므로 패키지에 포함됩니다.

덧셈과 뺄셈은 회로에 전혀 차이가 없습니다. 정수의 소위 2의 보수 표현 을 읽으면 정수 의 특성에 관계 없이이 연산이 정확히 동일한 방식으로 수행 될 수 있도록 영리하게 설계되었음을 알 수 있습니다.

비교도 같은 방식으로 작동합니다. 결과를 빼고 무시하는 것 외에는 유일한 차이점은 조건부 분기 (점프) 명령에 있습니다.이 명령은 조건부 분기 (점프) 명령에 있습니다. 선행 (비교) 명령. 이 답변에서 /programming//a/9617990/773113 인텔 x86 아키텍처에서 어떻게 작동하는지에 대한 설명을 찾을 수 있습니다. 발생하는 조건은 조건부 점프 명령을 부호있는 또는 부호없는 것으로 지정하는 것은 검사하는 플래그에 따라 다릅니다.


1
내 질문은이 모든 것을 가정했습니다. 알고리즘으로 나는보다 작은 규칙이 다른 것을 의미했습니다. 내가 보는 비용에는 많은 추가 지침이 있습니다. 높은 수준의 프로그램이 데이터를 비트 패턴으로보고자한다면, 컴파일러에 의해 쉽게 구현 될 수 있습니다
jtw

3
@jtw-그러나 요점은 그러한 추가 명령어는 실제로 부호가있는 숫자에 필요한 명령어 와 매우 유사 하며 필요한 거의 모든 회로를 공유 할 수 있다는 것 입니다. 두 유형을 모두 구현하는 데 드는 추가 비용은 거의 제로입니다.
Periata Breatta

1
예 그 여분의 분기 명령을 추가하는 작은 비용으로 제공하고 그들은 종종 연습에 유용, 내 질문에 대한 대답
JTW

1
"부호없는 곱셈은 나누기와 곱셈과 관련하여 약간의 처리가 필요하다" 고 생각합니다. 부호없는 값으로 곱셈과 나눗셈이 더 쉽습니다. 부호있는 피연산자를 처리하려면 추가 처리가 필요합니다.
Cody Grey

@CodyGray 나는 누군가가 이것을 말할 것이라고 알았습니다. 물론 그렇습니다. 이것은 내 진술의 이유이며, 간결성을 위해 원래 생략했습니다. 서명 된 버전이 너무 유용하기 때문에 CPU는 부호없는 전용 곱셈과 나눗셈을 제공 할 수 없었습니다. 실제로 서명 된 곱셈과 나눗셈은 필수입니다. 부호없는 옵션입니다. 따라서 서명되지 않은 것을 제공해야한다면 조금 더 많은 회로가 필요한 것으로 볼 수 있습니다.
Mike Nakis

7

마이크로 프로세서는 본질적으로 부호가 없습니다. 부호있는 숫자는 다른 방식이 아니라 구현 된 것입니다.

컴퓨터는 부호있는 숫자 없이도 잘 작동 할 수 있습니다. 그러나 음수를 필요로하는 인간 인 우리는 부호가 발명되었습니다.


4
많은 마이크로 프로세서에는 다양한 작업을위한 부호있는 명령어와 부호없는 명령어가 있습니다.
whatsisname

1
@whatsisname : 반대입니다. 많은 마이크로 프로세서에는 서명되지 않은 명령어 만 있습니다. 서명 지침을 가지고있다. 이는 2s 보완 산술에서 비트 값이 날씨에 관계없이 숫자가 부호가 있거나 부호가 없으며 숫자를 읽는 방법이 해석의 문제 일 뿐이므로 컴파일러 기능으로 구현하기가 더 쉽기 때문입니다. 일반적으로 프로그래머가 컴파일러를 사용하지 않는다고 가정하는 오래된 마이크로 만 어셈블리 코드를 읽을 수 있도록 멋진 서명 된 명령을 가지고 있습니다.
slebetman

3

저장에 쉽게 사용할 수있는 비트가 하나 더 있으므로 음수에 대해 걱정할 필요가 없습니다. 그것보다 더 많은 것이 없습니다.

이 여분의 비트 가 필요한 곳의 예가 필요 하다면 살펴보면 충분히 찾을 수 있습니다.

가장 좋아하는 예는 체스 엔진의 비트 보드에서 비롯됩니다. 체스 판에는 64 개의 정사각형이 있으므로 unsigned long이동 생성을 중심으로 회전하는 다양한 알고리즘을위한 완벽한 스토리지를 제공합니다. 바이너리 연산 (및 시프트 연산 !!)이 필요하다는 사실을 고려하면 MSB가 설정되면 어떤 특수한 일이 발생하는지 걱정하지 않아도되는 이유를 쉽게 알 수 있습니다. 부호가있는 long으로 수행 할 수 있지만 부호없는 것을 사용 하는 것이 훨씬 쉽습니다.


3

순수한 수학 배경을 가진 사람은 관심있는 사람이 조금 더 수학적으로 이해해야합니다.

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의 보수로 덧셈과 곱셈 연산이 동일하기 때문에 이런 식으로 음의 정수를 나타내는 것이 좋습니다. 그런 다음 이진 표현이 나타내는 정수에 의존하는 작업의 문제 일뿐입니다.


나는 수학적 접근 방식을 좋아하지만 특정 큰 크기로의 승격만을 생각하는 대신 무한 길이의 이진수로 연산을 일반화하는 것이 더 좋다고 생각합니다. 가장 오른쪽에있는 k 자리가 0이고 결과의 가장 오른쪽에있는 k 자리가 1 인 숫자에서 1을 빼면, 무한한 비트 수로 수학을 수행하면 모든 비트가 1이된다는 것을 알 수 있습니다. 수학은 숫자의 맨 아래 비트를 제외한 모든 것을 무시합니다.
supercat

2

부호없는 정수를 기존 부호있는 정수로 CPU 디자인에 추가하기위한 구현 비용을 조사 할 수 있습니다.

일반적인 CPU에는 다음과 같은 산술 명령어가 필요합니다.

  • ADD (두 개의 값을 더하고 연산이 오버플로되면 플래그를 설정 함)
  • SUB (한 값에서 다른 값을 빼고 다양한 플래그를 설정합니다. 아래에서 설명하겠습니다)
  • CMP (기본적으로 'SUB 및 결과를 버리고 플래그 만 유지함')
  • LSH (왼쪽 시프트, 오버 플로우시 플래그 설정)
  • RSH (오른쪽 이동, 1이 이동하면 플래그 설정)
  • 플래그로부터의 운반 / 차입을 처리하는 위의 모든 명령어의 변형으로, CPU 레지스터보다 큰 유형에서 작동하도록 명령어를 편리하게 묶을 수 있습니다.
  • MUL (곱하기, 설정 플래그 등-보편적으로 사용할 수 없음)
  • DIV (나누기, 플래그 설정 등-많은 CPU 아키텍처에는 부족함)
  • 더 작은 정수 유형 (예 : 16 비트)에서 더 큰 정수 유형 (예 : 32 비트)으로 이동하십시오. 부호있는 정수의 경우이를 일반적으로 MOVSX라고합니다 (기호 확장으로 이동).

논리적 인 지침도 필요합니다 :

  • 0에 분기
  • 더 큰 지점
  • 적은 지점
  • 오버플로 지점
  • 위의 모든 부정적인 버전

부호있는 정수 비교에서 위의 분기를 수행하려면 가장 쉬운 방법은 SUB 명령이 다음 플래그를 설정하는 것입니다.

  • 제로. 빼기 결과 값이 0이면 설정합니다.
  • 과다. 빼기가 가장 중요한 비트에서 값을 빌린 경우 설정합니다.
  • 기호. 결과의 부호 비트로 설정하십시오.

그런 다음 산술 분기는 다음과 같이 구현됩니다.

  • 0에 분기 : 제로 플래그가 설정된 경우
  • 적은 지점 : 부호 플래그가 오버플로 플래그와 다른 경우
  • 더 크게 분기 : 부호 플래그가 오버 플로우 플래그와 같고 0 플래그가 지워진 경우.

이것들의 부정은 그것들이 어떻게 구현되는지 분명하게 따라야합니다.

따라서 기존 디자인은 이미 부호있는 정수에 대해 이들을 모두 구현합니다. 이제 부호없는 정수를 추가하기 위해해야 ​​할 일을 고려하십시오.

  • ADD-ADD의 구현은 동일합니다.
  • SUB-여분의 플래그를 추가해야합니다. 캐리 플래그는 레지스터의 최상위 비트를 넘어서 값을 빌릴 때 설정됩니다.
  • CMP-변경하지 않음
  • LSH-변하지 않습니다
  • RSH-부호있는 값의 올바른 시프트는 최상위 비트의 값을 유지합니다. 부호없는 값의 경우 대신 0으로 설정해야합니다.
  • MUL-출력 크기가 입력과 동일하면 특별한 처리가 필요 하지 않습니다 (x86 에는 특수 처리가 있지만 레지스터 쌍으로 출력 되었기 때문에이 기능은 실제로 거의 사용되지 않으므로주의하십시오) 부호없는 유형보다 프로세서에서 벗어날 수있는 더 확실한 후보)
  • DIV-변경이 필요하지 않습니다
  • 더 작은 유형에서 더 큰 유형으로 이동-MOVZX를 추가하고 확장없이 이동하십시오. MOVZX는 구현 이 매우 간단합니다.
  • 0의 분기-변경되지 않음
  • 적은 지점-캐리 플래그가 설정되면 점프합니다.
  • 더 크게 분기-캐리 플래그와 0을 모두 지우면 점프합니다.

각각의 경우에, 수정은 매우 간단하고 , 작은 회로 부분을 온 또는 오프로 게이팅하거나, 또는 새로운 플래그 레지스터를 추가함으로써 간단하게 구현 될 수 있음을 주목해야한다. 어쨌든 명령의 구현.

따라서 서명되지 않은 명령어를 추가하는 비용은 매우 적습니다 . 이 이유에 수행해야합니다 (배열의 오프셋 (offset)) 그 메모리 주소는 본래 부호없는 값입니다 유의하십시오. 프로그램이 메모리 주소를 조작하는 데 많은 시간을 소비하므로 올바르게 처리하는 유형이 있으면 프로그램을보다 쉽게 ​​작성할 수 있습니다.


감사합니다, 이것은 내 질문에 대답합니다, 비용은 작고 지침은 자주 유용합니다
jtw

1
부호없는 이중 크기 곱셈은 다중 정밀도 산술을 수행 할 때 필수적이며 RSA 암호화를 수행 할 때 전체 속도가 2 배 이상 향상되는 데 적합합니다. 또한 부호가있는 경우와 부호가없는 경우에는 구분이 다르지만 부호가없는 경우가 더 쉽고 나누기가 충분히 드물고 느리기 때문에 몇 가지 명령을 추가해도 크게 아프지 않을 것이므로 가장 간단한 방법은 부호없는 구분 구현하는 것입니다. 그런 다음 서명 처리 논리로 감싸십시오.
supercat

2

부호없는 숫자는 래핑 대수 고리가 필요한 상황을 처리하기 위해 주로 존재합니다 (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)를 사용하면 int16 비트 (즉, 리턴 1) 인 시스템에서 하나의 정의 된 동작 , int33 비트 이상 (0xFFFE0001 리턴) 인 다른 동작 및 "int"가있는 시스템의 경우 정의되지 않은 동작이 있습니다. [gcc는 보통 INT_MAX + 1u와 UINT_MAX 사이의 결과로 산술적으로 올바른 결과를 산출하지만, 때때로 그러한 값으로 실패하는 위 함수에 대한 코드를 생성합니다!]. 별로 도움이되지 않습니다.

그럼에도 불구하고, 숫자처럼 일관되게 또는 대수 고리처럼 일관되게 작동하는 유형이 없다고해서 어떤 종류의 프로그래밍에 대수 고리 유형이 거의 없어야한다는 사실은 변하지 않습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.