2013-04-19 4 views
7
나는 내가 unsigned에 대해 std::abs(int)을 비교있을 때 서명 대 부호없는 비교를 위해 경고 얻고있다

. 실제로 std::abs은 서명 된 값을 반환합니다. 그 선택은 왜 만들어 졌습니까? 절대 값이 부호있는 유형으로 표현 될 수없는 음수 값 문제를 해결했을 것입니다.왜 표준 : ABS 반환 서명 않는 유형

그리고, 뭔가 청소기는이보다 경고를 방지하기 위해 (즉 캐스트하지 않고,)이 있습니까?

#include <cassert> 
#include <cstdlib> 

// max(1, lhs + rhs). (lhs must be > 0) 
unsigned add(unsigned lhs, int rhs) 
{ 
    return 
    (0 < rhs || static_cast<unsigned>(-rhs) < lhs 
    ? rhs + lhs 
    : 1); 
} 

int main() 
{ 
    assert(add(42, -41) == 1); 
    assert(add(42, 0) == 43); 
    assert(add(42, 1) == 43); 
    assert(add(42, -51) == 1); 
} 
+0

나는이 표준 근거에 많은 영향을 미쳤다 의심하지만, 실제로 unsigned'가 int''의 모든 절대 값을 나타낼 수'보장되지 않습니다. 이론 상으로는'int'가 33 비트 2의 보수이고'unsigned'가 32 비트 인 적합 구현을 할 수 있습니다. 그 구현에서'int'도'unsigned'도'INT_MIN'의 절대 값을 나타낼 수 없습니다. 왜 그런 구현이 필요한지 확실하지 않지만 합법적이므로 제안은 엄격하게 * 문제를 해결하지 않습니다. 표준은'abs (INT_MIN)'을 할 수없는 곳에 구현을 허용합니다! –

+0

그리고 실제로, 당신이 할 수있는 int' '의 하나 개의 값이 있다는 사실은'abs' 정말 당신이 할 수있는 int''의 하나 개의 값이 있다는 사실보다 더 불편하지 않다 '-'. 그리고 마찬가지로'++ '를 할 수없는 값. C 및 C++의 작성자는 정의되지 않은 오버플로 동작을 제거 할만큼 충분히 미워하지 않습니다. –

+0

@SteveJessop §3.9.1-3 ('unsigned int'와'int'를위한 같은 양의 저장 공간과 같은 객체 표현)에서 어떻게 가능합니까? –

답변

6

간단히 대답하면 반환 유형이 abs이 입력 유형과 동일하도록하는 것입니다. 이것은 정확히 당신이 원하는대로, 대부분의 시간. 복근을 호출 할 때

은 대부분, 당신은 모든 요소가 같은 유형 방정식을 다루고있는 (또는 당신이 경고를 얻을 것) 당신은 그 방정식에 일부 변수의 크기를 사용하고 싶습니다. 그렇다고해서 방정식의 변수 중 하나의 유형을 변경하고 싶지는 않습니다. 그것은 당신이 언급하는 종류의 이슈/경고를 줄 것입니다.

그래서, 간단히 말해서 일반적인 및 부호있는 변수의 절대 값을 요청할 때 동일한 입력 및 출력 타입 원하는 더욱 자연 스럽다. 가치의 크기는 일반적으로 지수로 사용되지 않습니다.

+0

+1 절대적으로. 결국 수학 함수이고 엉망이되어서는 안됩니다. 'std :: abs (1.0)'이'unsigned double'을 반환하는 것을 원하지 않습니다. 마찬가지로'std :: floor'는'int'를 반환하지 않습니다. (ok, this one –

+0

@ChristianRau : '서명되지 않은 이중'이 무엇인지는 모르겠지만, 나는 확실히 원한다. ;-) 그리고 어떤 사람들은 부호없는 정수 타입에 관해서도 똑같이 말하십시오. –

+0

@ChristianRau 정확히 내 요점! 또한 @SteveJessop에 동의하는 이유는'unsigned double '소리가 아주 크게 들리지 않고 표준에서 빠뜨리지도 않는다는 것입니다. – Agentlien

2

이것은 선택의 여지가 없습니다. 정의입니다. abs는 템플릿을 통해 구현되며 원래 값이 저장된 유형을 반환합니다. 부호있는 정수의 절대 값이 항상 원래 데이터 유형에 맞기 때문에 결과는 항상 유효합니다. 대상 데이터 형식에 대한 명시 적 형변환은 경고를 없애기에 충분해야합니다. ...

+5

"부호가있는 정수의 절대 값은 항상 적합 할 것입니다. 자신의 원래 데이터 형식으로 "- 사실이 아닙니다. 거의 모든 구현에서'INT_MIN'의 절대 값은'int'에 들어 가지 않습니다. 그리고'abs (INT_MIN)'는 오버 플로우를 일으 킵니다. –

+1

'abs는 템플릿을 통해 구현됩니다 .' 내가 알고있는 [abs] (http://en.cppreference.com/w/cpp/numeric/math/abs)은 템플릿이 아닙니다. –

+0

다음은 표준에 따라 존재하는 abs의 변형입니다. http://en.cppreference.com/w/cpp/numeric/math/abs 템플릿으로 사용되는 이들 중 유일한 것은 템플릿 유형을 입력으로 사용하는 것입니다 . (valarray 및 복합체). – Agentlien

3

C++ 11에서 당신은 당신의 자신의 자동 캐스트 할 수 있도록 작성할 수

#include <utility> 

template< typename T > 
typename std::make_unsigned<T>::type abs(T x) 
{ 
    //We need to cast before negating x to avoid the overflow. 
    return x < 0? -static_cast<std::make_unsigned<T>::type>(x) : x; 
} 

나는, -Wall 옵션을 시도 아무런 경고 없어.

+1

이 코드는 여전히 INT_MIN이 전달 될 때 UB를 가지며 절대 값을 표현할 수없는 음수 값의 문제를 해결하지 않습니다. 그러나 당신이 그것을 사용할 때마다'static_cast' 타이핑을 저장하지 않습니다. –

+0

나는 너무 생각했지만 시도했다. \t int x = std :: numeric_limits :: min(); \t 부호없는 y = my_abs (x); \t \tcout << x << endl; \t cout << y << endl; – fstamour

+0

그 점은 -2^(N-1)과 같은 N 비트 부호있는 정수를 표현할 수있는 가장 큰 숫자이므로 같은 형식 (즉, N 비트 부호있는 정수)으로 절대 값을 나타낼 수 없다는 것입니다 2^(N-1) -1이다. 하지만 std :: make_unsigned :: type은 2^N에 부호없는 값을 부여하는데, 2^N은 최대 값이 2^N이며, 이는 같은 양의 비트를 가진 임의의 부호있는 값보다 큽니다. – fstamour