C에 부호없는 수레가없는 이유는 무엇입니까?


131

나는 그 질문이 이상해 보인다. 프로그래머는 때때로 너무 많이 생각합니다. 읽어주세요 ...

CI의 사용 signedunsigned정수 많이. 부호없는 정수를 부호없는 변수에 할당하는 것과 같은 일을하면 컴파일러가 경고한다는 사실이 마음에 듭니다. 부호없는 정수와 훨씬 더 많은 부호를 비교하면 경고가 표시됩니다.

나는이 경고를 좋아한다. 그들은 내 코드를 올바르게 유지하도록 도와줍니다.

우리는 왜 수레에 대해 같은 사치를 가지고 있지 않습니까? 제곱근은 절대 음수를 반환하지 않습니다. 음의 float 값이 의미가없는 다른 곳도 있습니다. 부호없는 플로트에 대한 완벽한 후보.

Btw-수레에서 부호 비트를 제거하여 얻을 수있는 단일 정밀도의 비트에 대해서는 열의가 아닙니다. 나는 float그들이 지금처럼 s에 매우 만족 합니다. 때로는 부동 소수점을 부호없는 것으로 표시하고 정수와 동일한 종류의 경고를 얻고 싶습니다.

부호없는 부동 소수점 숫자를 지원하는 프로그래밍 언어를 알지 못합니다.

왜 존재하지 않는지 아십니까?


편집하다:

나는 x87 FPU에 부호없는 수레를 다루는 지시가 없다는 것을 알고 있습니다. 부호있는 부동 명령어를 사용하십시오. 부호있는 정수의 오버플로가 정의되지 않은 것과 같은 방식으로 오용 (예 : 0 미만으로 간주)이 정의되지 않은 동작으로 간주 될 수 있습니다.


4
흥미롭게도, 서명 유형 확인이 도움이 된 사례를 게시 할 수 있습니까?

litb, 당신의 의견은 나에게 지시 되었습니까? 그렇다면, 나는 그것을 얻지

이 인수의 절대 값을 반환하기 때문에 Iraimbilanja 그래 :) 팹은 음수를 반환 할 수 없습니다
요하네스 SCHAUB을 - litb

Right.i는 가상의 부호없는 플로트가 어떻게 간결함을 도울 수 있는지 묻지 않았습니다. 내가 요청한 것 : 어떤 상황에서 pipenbrinck가 Int signedness typechecking이 도움이 되었습니까 (유인물에 대해 동일한 메커니즘을 사용하도록 유도). typesafety와 관련하여

1
지점 내 검사를위한 부호없는 마이크로 최적화가 있습니다 : ((unsigned) (p-min)) <(max-min), 분기가 하나 뿐이지 만 항상 그렇듯이 프로파일 링하는 것이 가장 좋습니다 실제로 도움이됩니다 (대부분 386 코어에서 사용 했으므로 최신 CPU가 어떻게 대처하는지 알 수 없습니다).
Skizz

답변:


114

C ++에서 부호없는 부동 소수점을 지원하지 않는 이유는 CPU가 실행할 동등한 기계 코드 작업이 없기 때문입니다. 따라서 그것을 지원하는 것은 매우 비효율적입니다.

만약 C ++이 그것을 지원했다면, 때때로 부호없는 float를 사용하고 성능이 막 죽었 음을 깨닫지 못할 수 있습니다. C ++에서 지원하는 경우 모든 부동 소수점 연산이 서명되어 있는지 여부를 확인해야합니다. 그리고 수백만 개의 부동 소수점 연산을 수행하는 프로그램의 경우 이는 허용되지 않습니다.

따라서 하드웨어 구현자가 지원하지 않는 이유는 무엇입니까? 그리고 그에 대한 대답은 원래 정의되지 않은 부동 표준이 없다는 것입니다. 언어는 이전 버전과 호환되기를 원하기 때문에 언어를 추가하더라도 언어를 사용할 수 없습니다. 부동 소수점 사양을 보려면 IEEE 표준 754 부동 소수점을 살펴보십시오 .

부동 소수점 또는 이중을 캡슐화하고 음수를 전달하려고하면 경고를 던지는 부호없는 부동 소수점 클래스를 만들어서 부호없는 부동 소수점 유형을 갖지 않을 수 있습니다. 이것은 덜 효율적이지만, 당신이 그들을 강하게 사용하지 않는다면 아마 약간의 성능 손실에 신경 쓰지 않을 것입니다.

나는 부호없는 플로트를 갖는 것이 유용하다는 것을 분명히 봅니다. 그러나 C / C ++는 안전을 능가하는 모든 사람에게 가장 적합한 효율성을 선택하는 경향이 있습니다.


17
C / C ++에서는 언어를 구현하기 위해 특정 기계 코드 작업이 필요하지 않습니다. 초기 C / C ++ 컴파일러는 FPU가없는 CPU 인 386에 대한 부동 소수점 코드를 생성 할 수 있습니다! 컴파일러는 FPU 명령어를 에뮬레이트하기 위해 라이브러리 호출을 생성합니다. 따라서 CPU 지원없이 ufloat을 수행 할 수 있습니다
Skizz

10
Skizz는 맞지만 Brian은 이미 이것을 해결했습니다. 동등한 기계 코드가 없기 때문에 성능이 비교할 때 끔찍합니다.
Anthony

2
@Brian R. Bondy : "여기서 CPU를 실행하기위한 동등한 머신 코드 작업이 없기 때문에 ..." 더 간단한 용어로 설명해 주시겠습니까?
Lazer

2
OP가 서명되지 않은 부동 소수점에 대한 지원을 원했던 이유는 경고 메시지에 대한 것이기 때문에 실제로는 컴파일러의 코드 생성 단계와 관련이 없으며 형식 검사를 수행하는 방법과 만 관련이 있으므로 기계 코드에서 지원하는 것은 관련이 없습니다. (질문의 맨 아래에 추가 된 것처럼) 정상적인 부동 소수점 명령어가 실제 실행에 사용될 수 있습니다.
Joe F

2
이것이 왜 성능에 영향을 미치는지 잘 모르겠습니다. int의 경우 와 마찬가지로 모든 부호 관련 유형 검사는 컴파일 타임에 발생할 수 있습니다. OP는 의미없는 특정 작업이 수행되지 않도록 컴파일 타임 검사를 통해 unsigned float정기적으로 구현할 것을 제안합니다 float. 플로트의 서명 여부에 관계없이 결과로 생성되는 기계 코드 및 성능은 동일 할 수 있습니다.
xanderflood

14

C / C ++에서 부호있는 정수와 부호없는 정수에는 큰 차이가 있습니다.

value >> shift

부호있는 값은 최상위 비트를 변경하지 않고 그대로두고 (부호 확장), 부호없는 값은 최상위 비트를 지 웁니다.

부호없는 부동 소수점이없는 이유는 음수 값이 없으면 모든 종류의 문제에 빠르게 부딪 치기 때문입니다. 이걸 고려하세요:

float a = 2.0f, b = 10.0f, c;
c = a - b;

c는 어떤 가치가 있습니까? -8. 그러나 음수가없는 시스템에서는 이것이 무엇을 의미합니까? FLOAT_MAX-아마도 8? 실제로 FLOAT_MAX-8은 정밀 효과로 인해 FLOAT_MAX이므로 작동하지 않으므로 일이 훨씬 까다로워집니다. 좀 더 복잡한 표현의 일부인 경우 :

float a = 2.0f, b = 10.0f, c = 20.0f, d = 3.14159f, e;
e = (a - b) / d + c;

2의 보수 시스템의 특성으로 인해 정수에는 문제가되지 않습니다.

또한 표준 수학 함수를 고려하십시오. sin, cos 및 tan는 입력 값의 절반에 대해서만 작동하며 값 로그 <1을 찾을 수없고 2 차 방정식을 풀 수 없습니다. x = (-b +/- root ( bb-4.ac)) / 2.a 등. 실제로 복잡한 함수에서는 어딘가 음수 값을 사용하는 다항식 근사치로 구현되는 경향이 있으므로 복잡한 함수에서는 작동하지 않을 수 있습니다.

따라서 부호없는 수레는 쓸모가 없습니다.

그러나 그것이 범위 값을 플로트 값으로 검사하는 클래스가 유용하지 않다는 것을 의미하지는 않습니다. 예를 들어 RGB 계산과 같이 주어진 범위로 값을 고정하고 싶을 수 있습니다.


@Skizz : 표현이 문제라면 누군가가 효율적인 수레를 저장하는 방법을 고안 할 수 있다면 2's complement부호없는 수레에 문제가 없을 것입니까?
Lazer

3
value >> shift for signed values leave the top bit unchanged (sign extend) 확실합니까? 적어도 음의 부호있는 값에 대해서는 구현 정의 동작이라고 생각했습니다.
Dan

@ Dan : 최근의 표준을 보았고 실제로 구현이 정의되어 있음을 나타냅니다. 부호 확장 명령으로 오른쪽 시프트가없는 CPU가있는 경우에 대비합니다.
Skizz


1
부동 소수점은 일반적으로 줄 바꿈 대신 포화 (-/ + Inf)합니다. 부호없는 빼기 오버플로가 포화 0.0되거나 Inf 또는 NaN 으로 포화 될 것으로 예상 할 수 있습니다 . 또는 질문에 대한 수정에서 제안 된 OP와 같이 정의되지 않은 행동이어야합니다. 다시 : 삼각 함수 : 따라서 부호없는 입력 버전 등을 정의하지 말고 sin반환 값을 부호있는 것으로 취급하십시오. 이 문제는 float를 부호없는 float로 대체 하는 것이 아니라 unsigned float새로운 유형으로 추가 하는 것을 제안하지 않았습니다 .
Peter Cordes

9

(옆으로, Perl 6을 사용하면

subset Nonnegative::Float of Float where { $_ >= 0 };

Nonnegative::Float다른 유형과 마찬가지로 사용할 수 있습니다 .)

부호없는 부동 소수점 연산에 대한 하드웨어 지원은 없으므로 C는이를 지원하지 않습니다. C는 대부분 "휴대용 어셈블리", 즉 특정 플랫폼에 묶이지 않고 금속에 가깝도록 설계되었습니다.

[편집하다]

C는 어셈블리와 같습니다. 당신이 보는 것은 정확히 당신이 얻는 것입니다. 암시적인 "이 플로트가 음수가 아닌지 확인하겠습니다"는 디자인 철학에 위배됩니다. 정말로 원한다면 추가 assert(x >= 0)하거나 유사하게 할 수 있지만 명시 적으로해야합니다.


svn.perl.org/parrot/trunk/languages/perl6/docs/STATUS 는 예라고 말하지만 of ...구문 분석하지 않습니다.
ephemient

8

서명 된 int가 제공 할 수있는 것보다 더 큰 가치 마진이 필요하기 때문에 서명되지 않은 int가 생성되었다고 생각합니다.

플로트는 훨씬 큰 마진을 가지므로 부호없는 플로트에 대한 '물리적'필요는 없었습니다. 그리고 당신이 당신의 질문에 자신을 지적함에 따라, 추가 1 비트 정밀도는 죽일 것이 없습니다.

편집 : Brian R. Bondy답변을 읽은 후 내 대답을 수정해야합니다. 기본 CPU에 서명되지 않은 부동 소수점 연산이 없었 음이 분명합니다. 그러나 나는 이것이 위에서 언급 한 이유에 따라 디자인 결정이라고 생각합니다. ;-)


2
또한 정수의 덧셈과 뺄셈은 부호가 있거나 부호가없는 것과 같은 부동 소수점입니다. 그러한 기능의 상대적으로 낮은 한계 유틸리티가 주어지면 부호있는 플로트와 부호없는 플로트를 지원하기 위해 추가 작업을 수행하는 사람은 누구입니까?
ephemient

7

Treb이 올바른 길을 가고 있다고 생각합니다. 부호없는 해당 유형이있는 정수의 경우 더 중요합니다. 그것들은 비트 시프 팅 에 사용되며 비트 맵에 사용 되는 것들입니다 . 부호 비트가 막 시작되었습니다. 예를 들어, 음수 값을 오른쪽으로 이동하면 결과 값은 C ++로 정의 된 구현입니다. 부호없는 정수로 오버플로하거나 오버플로를 수행하면 의미가 완벽하게 정의되어 있습니다.

따라서 정수의 경우 최소한 경고를 제공하는 것보다 별도의 부호없는 유형이 필요합니다. 수레에 대해 위의 모든 사항을 고려할 필요는 없습니다. 따라서 하드웨어 지원이 실제로 필요하지 않으며 C는 이미 그 시점에서 지원하지 않습니다.


5

제곱근은 절대 음수를 반환하지 않습니다. 음의 float 값이 의미가없는 다른 곳도 있습니다. 부호없는 플로트에 대한 완벽한 후보.

C99는 복소수와 제네릭 형식의 sqrt를 지원하므로 sqrt( 1.0 * I)음수가됩니다.


주석 작성자 sqrt는 함수가 아닌 유형 일반 매크로를 언급하고 있다는 점에서 약간의 광택을 강조 했으며 실제 구성 요소에 대한 복합 자르기를 통해 스칼라 부동 소수점 값을 반환합니다.

#include <complex.h>
#include <tgmath.h>

int main () 
{
    complex double a = 1.0 + 1.0 * I;

    double f = sqrt(a);

    return 0;
}

또한 복소수의 sqrt의 실제 부분이 양수 또는 0이고 sqrt (1.0 * I)가 sqrt (0.5) + sqrt (0.5) * I -1.0이 아니기 때문에 brain-fart도 포함합니다.


예, 그러나 복잡한 숫자로 작업하는 경우 다른 이름의 함수를 호출합니다. 또한 반환 유형이 다릅니다. 그래도 좋은 지적입니다!
Nils Pipenbrinck

4
sqrt (i)의 결과는 복소수입니다. 그리고 복소수는 주문되지 않기 때문에 복소수는
부정적

1
quinmars, csqrt가 아닙니까? 아니면 C 대신 수학에 대해 이야기합니까? 나는 그것이 좋은 포인트 :) 있다는 어쨌든 동의
요하네스 SCHAUB을 - litb

실제로 저는 수학에 대해 이야기하고있었습니다. 나는 c의 복소수를 다루지 않았다.
quinmars

1
"제곱근은 절대 음수를 반환하지 않습니다." -> sqrt(-0.0)종종 생산합니다 -0.0. 물론 -0.0은 음수 이 아닙니다 .
chux-복원 모니카

4

IEEE 부동 소수점 사양에만 서명하고 대부분의 프로그래밍 언어에서 사용한다는 것이 달려 있습니다.

IEEE-754 부동 소수점 숫자에 대한 Wikipedia 기사

편집 : 또한 다른 사람들이 지적했듯이 대부분의 하드웨어는 음이 아닌 부동 소수점을 지원하지 않으므로 하드웨어 지원이 있기 때문에 일반적인 종류의 부동 소수점이 더 효율적입니다.


는 IEEE-754 표준이 등장하기 전에 C 긴 도입
phuclv

@phuclv 일반적인 부동 소수점 하드웨어도 아니었다. "몇 년 후"표준 C에 채택되었습니다. 아마도 인터넷에 떠 다니는 문서가있을 것입니다. 또한 위키 백과 기사에는 C99가 언급되어 있습니다.
Tobias Wärre

무슨 말인지 모르겠어요 당신의 대답에는 "하드웨어"가 없으며, IEEE-754는 C 이후에 태어 났기 때문에 C에서 부동 소수점 유형은 훨씬 나중에 C에 도입되지 않는 한 IEEE-754 표준에 의존 할 수 없습니다
phuclv

@phuclv C는 휴대용 어셈블리로도 알려져 있으므로 하드웨어에 매우 가깝습니다. 언어는 (내 시간 전에) float가 C로 구현되어 있어도 수년에 걸쳐 기능을 얻습니다. 아마도 소프트웨어 기반 작업이었고 상당히 비쌌을 것입니다. 이 질문에 대답 할 당시, 나는 지금보다 내가 설명하려고하는 것을 더 잘 이해하고있었습니다. 허용되는 답변을 보면 IEE754 표준을 언급 한 이유를 이해할 수 있습니다. 내가 이해하지 못하는 것은 당신이 받아 들일 수없는 10 살짜리 대답에 nitpicked한다는 것입니다.
Tobias Wärre

3

주된 이유는 부호없는 부동 소수점이 부호없는 정수에 비해 실제로 사용이 제한되어 있기 때문입니다. 나는 하드웨어가 그것을 지원하지 않기 때문에 그 주장을 사지 않습니다. 구형 프로세서에는 부동 소수점 기능이 전혀 없었으며 소프트웨어에서 모두 에뮬레이션되었습니다. 서명되지 않은 플로트가 유용했다면, 소프트웨어에서 먼저 구현되었을 것이고 하드웨어는 그에 따랐을 것입니다.


4
C의 첫 번째 플랫폼 인 PDP-7에는 옵션 하드웨어 부동 소수점 장치가있었습니다. C의 다음 플랫폼 인 PDP-11에는 하드웨어에 32 비트 플로트가있었습니다. 80x86은 한 세대 뒤에 왔으며 일부 기술은 뒤쳐졌습니다.
ephemient 2018

3

C에서 부호없는 정수 유형은 추상 대수 고리의 규칙을 따르는 방식으로 정의됩니다. 예를 들어, X 및 Y 값의 경우 XY를 Y에 추가하면 X가 생성됩니다. 부호없는 정수 유형은 다른 숫자 유형 (또는 다른 크기의 부호없는 유형)과의 변환을 포함하지 않는 모든 경우에이 규칙을 준수합니다. 그 보증은 이러한 유형의 가장 중요한 기능 중 하나입니다. 경우에 따라 부호없는 유형 만 제공 할 수있는 추가 보증과 함께 음수를 나타내는 기능을 포기하는 것이 좋습니다. 부호가 있든 없든 부동 소수점 유형은 대수 고리의 모든 규칙을 준수 할 수 없습니다 (예 : X + YY가 X와 동일하다는 것을 보장 할 수 없음). 심지어 그들은 심지어 어떤 가치는 그들 자신과 다른 것을 요구함으로써 동등성 등급의 규칙을 따를 수있게한다. "부호없는"부동 소수점 유형이 일반 부동 소수점 유형이 할 수없는 공리를 따를 수 있다고 생각하지 않으므로 어떤 이점이 있는지 잘 모르겠습니다.


1

IHMO 하드웨어 또는 소프트웨어에서 부호있는 부동 소수점 유형과 부호없는 부동 소수점 유형을 모두 지원하는 것이 너무 번거로울 수 있기 때문입니다

정수 유형의 우리가 활용할 수 동일한 에 대한 논리 단위 모두 서명 부호없는 정수 연산 하기 때문에, 2의 보수의 좋은 속성을 사용하여 대부분의 경우이 결과는 이러한 경우에 동일 비 확대 MUL, 추가, 서브에 대한 대부분의 비트 연산. 서명 된 버전과 서명되지 않은 버전을 구분하는 작업의 경우 여전히 대부분의 논리를 공유 할 수 있습니다 . 예를 들어

  • 산술 및 논리 시프트는 상단 비트에 대한 필러의 약간의 변화 만 필요합니다.
  • 확대 곱셈은 주요 부분에 동일한 하드웨어를 사용 하고 결과를 조정 하여 부호를 변경 하기 위해 별도의 논리를 사용할 수 있습니다 . 실제 승수에 사용되는 것은 아니지만 가능합니다.
  • 부호있는 비교는 최상위 비트를 토글하거나을 추가INT_MIN 하여 부호없는 비교로 변환하거나 그 반대로 쉽게 변환 할 수 있습니다 . 이론적으로는 하드웨어에서는 사용되지 않지만 8080 또는 8051과 같은 한 가지 유형의 비교 만 지원 하는 시스템에서는 유용합니다.

1의 보수를 사용하는 시스템은 단순히 최하위 비트로 둘러싸인 캐리 비트이기 때문에 로직을 약간 수정하면됩니다. 부호 크기 시스템에 대해서는 확실하지 않지만 내부에서 1의 보수사용 하는 것처럼 보이 므로 동일한 것이 적용됩니다.

불행하게도 우리는 부동 소수점 유형에 대해 그렇게 사치하지 않습니다. 부호 비트를 해제함으로써 부호없는 버전을 갖게됩니다. 그러나 우리는 그 비트를 무엇에 사용해야합니까?

  • 지수에 범위를 더하여 범위를 증가시킵니다.
  • 가수에 추가하여 정밀도를 높입니다. 일반적으로 범위보다 정밀도가 더 필요하므로 더 유용합니다.

그러나 더 넓은 가치 범위를 수용 하려면 두 가지 선택 모두 더 큰 가산기 가 필요합니다 . 이는 가산기의 최상위 비트가 거의 사용되지 않는 동안 로직의 복잡성을 증가시킵니다. 곱셈, 나눗셈 또는 기타 복잡한 연산에는 더 많은 회로가 필요합니다.

소프트웨어 부동 소수점을 사용하는 시스템에서는 메모리가 너무 비싸거나 예상하지 못한 시간 동안 예상하지 못한 각 기능에 대해 2 가지 버전이 필요합니다.

그러나 C가 발명되기 오래 전에 부동 소수점 하드웨어가 존재 했기 때문에 위에서 언급 한 이유로 C에서 선택하는 것은 하드웨어 지원 부족 때문이라고 생각합니다

즉 , 주로 Khronos 그룹의 10 비트 및 11 비트 부동 소수점 유형과 같은 이미지 처리를 위해 특수화 된 부호없는 부동 소수점 형식 이 여러 개 있습니다.


0

C 컴파일러가 대상으로하는 기본 프로세서에는 부호없는 부동 소수점 숫자를 처리하는 좋은 방법이 없기 때문입니다.


기본 프로세서에 부호있는 부동 소수점 숫자를 처리하는 좋은 방법이 있습니까? C는 부동 소수점 보조 프로세서가 독특하고 보편적이지 않을 때 인기를 얻었습니다.
David Thornley

1
나는 모든 역사적인 타임 라인을 알지 못하지만 서명 된 플로트에 대한 하드웨어 지원이 새롭게 등장했습니다. 언어 설계자는이를 지원할 수 있지만 컴파일러 백엔드는 대상 아키텍처에 따라 다양한 수준의 지원을 제공합니다.
브라이언 엔싱크

0

좋은 질문.

당신이 말했듯이, 컴파일 타임 경고 만하고 동작에 변화가 없다면 기본 하드웨어는 영향을받지 않으므로 C ++ / 컴파일러 변경 일뿐입니다.

나는 이전에 같은 것을 이겼지 만, 문제는 : 그것은별로 도움이되지 않습니다. 기껏해야 컴파일러는 정적 할당을 찾을 수 있습니다.

unsigned float uf { 0 };
uf = -1f;

또는 최소한으로 더 길다

unsigned float uf { 0 };
float f { 2 };
uf -= f;

그러나 그것은 그것에 관한 것입니다. 부호없는 정수 유형을 사용하면 정의 된 랩 어라운드도 얻습니다. 즉 모듈 식 산술처럼 작동합니다.

unsigned char uc { 0 };
uc -= 1;

이 'uc'뒤에 255의 값이 있습니다.

이제 부호없는 float 유형이 주어지면 동일한 시나리오에서 컴파일러가 수행하는 작업은 무엇입니까? 컴파일 타임에 값을 모르는 경우 먼저 계산을 실행 한 다음 부호 검사를 수행하는 코드를 생성해야합니다. 그러나 그러한 계산 결과가 "-5.5"라고 말할 때-부호없는 것으로 선언 된 float에 어떤 값을 저장해야합니까? 정수형과 같은 모듈 식 산술을 시도 할 수는 있지만 그 자체의 문제가 있습니다. 보유 할 수있는 가장 큰 고유 한 가치를 추구하는 것은 가치를 예측할 때 실제로 효과가 없습니다. "NaN"이 후보입니다.

마지막으로 모듈로가 잘 정의되어 있기 때문에 고정 소수점 수에는 문제가되지 않습니다.

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