음수의 경우 -1을, 양수의 경우 +1을 반환하는 함수를 원합니다. http://en.wikipedia.org/wiki/Sign_function 내 자신을 작성하기는 쉽지만 어딘가에 표준 라이브러리에 있어야하는 것 같습니다.
편집 : 구체적으로, 나는 수레에서 작동하는 함수를 찾고있었습니다.
x==0. IEEE 754 에 따르면 , 음의 0과 양의 0은 동일한 것으로 비교해야합니다.
음수의 경우 -1을, 양수의 경우 +1을 반환하는 함수를 원합니다. http://en.wikipedia.org/wiki/Sign_function 내 자신을 작성하기는 쉽지만 어딘가에 표준 라이브러리에 있어야하는 것 같습니다.
편집 : 구체적으로, 나는 수레에서 작동하는 함수를 찾고있었습니다.
x==0. IEEE 754 에 따르면 , 음의 0과 양의 0은 동일한 것으로 비교해야합니다.
답변:
아무도 타입 안전 C ++ 버전을 아직 게시하지 않았습니다.
template <typename T> int sgn(T val) {
return (T(0) < val) - (val < T(0));
}
혜택:
copysign특히 승격 한 다음 다시 좁힐 필요가있는 경우 느립니다. 이것은 분기가 없으며 훌륭하게 최적화됩니다.주의 사항 :
< 0검사 의 일부 -Wtype-limits는 서명되지 않은 유형으로 인스턴스화 될 때 GCC의 경고를 트리거 합니다. 몇 가지 과부하를 사용하여이를 피할 수 있습니다.
template <typename T> inline constexpr
int signum(T x, std::false_type is_signed) {
return T(0) < x;
}
template <typename T> inline constexpr
int signum(T x, std::true_type is_signed) {
return (T(0) < x) - (x < T(0));
}
template <typename T> inline constexpr
int signum(T x) {
return signum(x, std::is_signed<T>());
}
(첫 번째 경고의 좋은 예는 무엇입니까?)
std::copysign를 사용하면 4 개의 명령 (인라인 된), 분기 없음, 전적으로 FPU를 사용하는 훌륭한 코드가 될 것 같습니다. 대조적으로,이 답변에서 주어진 레시피는 훨씬 더 나쁜 코드를 생성합니다 (정수 단위와 FPU 사이에서 앞뒤로 이동하는 것을 포함하여 더 많은 명령어).
copysignint를 호출 하면 float / double로 승격되며 반환시 다시 좁혀 야합니다. 컴파일러가 프로모션을 최적화 할 수는 있지만 표준에서 보장하는 제안을 찾을 수 없습니다. 또한 copysign을 통해 signum을 구현하려면 0 사례를 수동으로 처리해야합니다. 성능 비교에이를 포함시켜야합니다.
나는 그것에 대한 표준 기능을 모른다. 그래도 재미있는 방법이 있습니다.
(x > 0) - (x < 0)
보다 읽기 쉬운 방법은 다음과 같습니다.
if (x > 0) return 1;
if (x < 0) return -1;
return 0;
삼항 연산자가 마음에 들면 다음과 같이 할 수 있습니다.
(x > 0) ? 1 : ((x < 0) ? -1 : 0)
x==0.
<는 >... 지정된 관계가 참이면 1을 산출하고 거짓이면 0을 산출합니다"
0은 "false"입니다. 다른 값은 "true"입니다. 그러나 관계형 및 등식 연산자는 항상 반환 0하거나 1표준 6.5.8 및 6.5.9를 참조하십시오. - 식의 값 a * (x == 42)중 하나입니다 0또는 a.
copysign적분에 사용하지 않습니다 x.
copysign ()이라는 C99 수학 라이브러리 함수가 있습니다.이 함수는 한 인수의 부호와 다른 인수의 절대 값을 가져옵니다.
result = copysign(1.0, value) // double
result = copysignf(1.0, value) // float
result = copysignl(1.0, value) // long double
값의 부호에 따라 +/- 1.0의 결과를 제공합니다. 부동 소수점 0은 부호가 있습니다. (+0)은 +1을 생성하고 (-0)은 -1을 생성합니다.
대부분의 답변이 원래의 질문을 놓친 것 같습니다.
C / C ++에 표준 부호 기능 (signum, sgn)이 있습니까?
표준 라이브러리에는 없지만 다음을 copysign통해 거의 같은 방식으로 사용할 수 있습니다copysign(1.0, arg) 에 실제 부호 함수가 boost있으며 이는 표준의 일부일 수도 있습니다.
#include <boost/math/special_functions/sign.hpp>
//Returns 1 if x > 0, -1 if x < 0, and 0 if x is zero.
template <class T>
inline int sign (const T& z);
원래 포스터의 질문에 대한 대답은 '아니요'입니다. 표준 C ++ sgn함수 는 없습니다 .
copysign()두 번째가 0.0이면 첫 번째 매개 변수를 0.0으로 만들지 않습니다. 다시 말해, 요한은 옳습니다.
C / C ++에 표준 부호 기능 (signum, sgn)이 있습니까?
예, 정의에 따라 다릅니다.
C99 이상에는 signbit()매크로가 있습니다.<math.h>
int signbit(실제 부동x); 매크로 반환 인수 값의 부호가 음수 인 경우에만, 제로가 아닌 값입니다. C11 §7.12.3.6signbit
그러나 OP는 조금 다른 것을 원합니다.
음수의 경우 -1을, 양수의 경우 +1을 반환하는 함수를 원합니다. ... 수레에서 작동하는 함수.
#define signbit_p1_or_n1(x) ((signbit(x) ? -1 : 1)
더 깊은 :
다음과 같은 경우 게시물이 구체적이지 않습니다 x = 0.0, -0.0, +NaN, -NaN..
클래식 signum()은 +1on x>0, -1on x<0및 0on으로 돌아갑니다 x==0.
많은 답변이 이미 다루어졌지만 다루지 않습니다 x = -0.0, +NaN, -NaN. 많은 수는 일반적으로 NaN (Not-a-Numbers )과 -0.0 이없는 정수 관점에 적합합니다 .
일반적인 답변은 signnum_typical() On 과 같은 기능을 -0.0, +NaN, -NaN하며 반환 0.0, 0.0, 0.0됩니다.
int signnum_typical(double x) {
if (x > 0.0) return 1;
if (x < 0.0) return -1;
return 0;
}
대신, 나는이 기능을 제안합니다 : On -0.0, +NaN, -NaN, 그것은 반환합니다 -0.0, +NaN, -NaN.
double signnum_c(double x) {
if (x > 0.0) return 1.0;
if (x < 0.0) return -1.0;
return x;
}
분기하지 않고 할 수있는 방법이 있지만 그리 좋지는 않습니다.
sign = -(int)((unsigned int)((int)v) >> (sizeof(int) * CHAR_BIT - 1));
http://graphics.stanford.edu/~seander/bithacks.html
그 페이지에있는 흥미롭고 지나치게 많은 다른 것들도 ...
sign = (v != 0) | -(int)((unsigned int)((int)v) >> (sizeof(int) * CHAR_BIT - 1));또는 sign = (v > 0) - (v < 0);입니다.
vint보다 넓지 않은 정수 타입 임을 의미합니다.
일반적으로 C / C ++에는 표준 signum 함수가 없으며 이러한 기본 함수가 없으면 이러한 언어에 대해 많은 정보를 제공합니다.
그 외에도, 나는 그러한 함수를 정의하는 올바른 접근 방식에 대한 대다수의 관점이 올바른 방식이라고 생각하며, 두 가지 중요한 경고를 고려하면 실제로 그 논쟁에 대한 논란은 논란의 여지가 없습니다.
시그넘 함수는 항상 유사하게하려면, 피연산자의 타입을 반환해야 abs()하기 때문에, 함수 시그넘은 후자 든 처리되면 보통 절대 값과 곱하기 위해 사용된다. 따라서 signum 의 주요 사용 사례는 비교가 아니라 산술이며, 후자는 고가의 정수에서 부동 소수점으로의 변환을 포함하지 않아야합니다.
부동 소수점 유형에는 하나의 정확한 0 값이 없습니다. +0.0은 "무한 위 0"으로, -0.0은 "무한 0 아래"로 해석 할 수 있습니다. 그것이 0을 포함하는 비교가 내부적으로 두 값을 모두 검사해야하는 이유이며, 이와 같은 표현은 x == 0.0위험 할 수 있습니다.
C와 관련하여 필자는 정수 유형을 사용하는 가장 좋은 방법은 실제로 (x > 0) - (x < 0)분기 를 사용 하지 않고 번역해야하며 3 가지 기본 연산 만 필요하므로 표현식 을 사용하는 것이라고 생각합니다 . 인수 유형과 일치하는 리턴 유형을 적용하는 인라인 함수를 가장 잘 정의하고 C11 define _Generic을 추가하여 이러한 함수를 공통 이름에 맵핑하십시오.
부동 소수점 값으로, 내가 C11을 기반으로 인라인 함수를 생각 copysignf(1.0f, x), copysign(1.0, x)그리고 copysignl(1.0l, x)길을 가야하는 것입니다, 그들은 또한있어 간단하기 때문에 가능성이 높은 지점이 없어야하고, 부동 소수점에 정수 뒷면에서 결과를 캐스팅이 필요하지 않은 추가 값. 부동 소수점 0 값의 특성, 처리 시간 고려 사항 및 부동 소수점 산술에서 올바른 -1 / +를 수신하는 것이 매우 유용하기 때문에 signum 의 부동 소수점 구현이 0을 반환하지 않을 것이라고 분명히 언급해야 합니다. 값이 0 인 경우에도 1 부호.
Nutshell의 C 사본은 유용한 copysign이라는 표준 함수가 있음을 보여줍니다. copysign (1.0, -2.0)은 -1.0을 반환하고 copysign (1.0, 2.0)은 +1.0을 반환하는 것처럼 보입니다.
응?
아니요, matlab과 같이 C ++에는 존재하지 않습니다. 나는 이것을 위해 내 프로그램에서 매크로를 사용합니다.
#define sign(a) ( ( (a) < 0 ) ? -1 : ( (a) > 0 ) )
#define sign(x) (((x) > 0) - ((x) < 0))습니다.
아래 과부하가 허용 된 답변은 실제로 -Wtype-limits를 트리거하지 않습니다 .
template <typename T> inline constexpr
int signum(T x, std::false_type) {
return T(0) < x;
}
template <typename T> inline constexpr
int signum(T x, std::true_type) {
return (T(0) < x) - (x < T(0));
}
template <typename T> inline constexpr
int signum(T x) {
return signum(x, std::is_signed<T>());
}
C ++ 11의 경우 대안이 될 수 있습니다.
template <typename T>
typename std::enable_if<std::is_unsigned<T>::value, int>::type
inline constexpr signum(T const x) {
return T(0) < x;
}
template <typename T>
typename std::enable_if<std::is_signed<T>::value, int>::type
inline constexpr signum(T const x) {
return (T(0) < x) - (x < T(0));
}
나에게는 GCC 5.3.1에 대한 경고가 발생하지 않습니다.
-Wunused-parameter경고 를 피하려면 명명되지 않은 매개 변수 만 사용하십시오.
주제를 벗어난 것이지만 이것을 사용합니다.
template<typename T>
constexpr int sgn(const T &a, const T &b) noexcept{
return (a > b) - (a < b);
}
template<typename T>
constexpr int sgn(const T &a) noexcept{
return sgn(a, T(0));
}
그리고 첫 번째 함수-두 개의 인수가있는 함수는 "표준"sgn ()에서 훨씬 더 유용하다는 것을 알았습니다. 가장 일반적으로 다음과 같은 코드에서 사용되기 때문입니다.
int comp(unsigned a, unsigned b){
return sgn( int(a) - int(b) );
}
vs.
int comp(unsigned a, unsigned b){
return sgn(a, b);
}
부호없는 유형에 대한 캐스트가없고 추가 빼기가 없습니다.
사실 나는 sgn ()을 사용 하여이 코드 조각을 가지고있다.
template <class T>
int comp(const T &a, const T &b){
log__("all");
if (a < b)
return -1;
if (a > b)
return +1;
return 0;
}
inline int comp(int const a, int const b){
log__("int");
return a - b;
}
inline int comp(long int const a, long int const b){
log__("long");
return sgn(a, b);
}
문제는 오래되었지만 이제는 이런 종류의 원하는 기능이 있습니다. 나는 왼쪽 시프트와 12 월이 아닌 래퍼를 추가했습니다.
C99의 부호 비트를 기반으로 래퍼 함수를 사용하면 원하는 동작을 정확하게 얻을 수 있습니다 (아래 코드 참조).
x의 부호가 음수인지 여부를 반환합니다.
이것은 무한대, NaN 및 0에도 적용될 수 있습니다 (0이 부호가없는 경우 양의 것으로 간주 됨)
#include <math.h>
int signValue(float a) {
return ((!signbit(a)) << 1) - 1;
}
NB : 부호 비트의 반환 값이 1로 지정되어 있지 않기 때문에 피연산자 not ( "!")을 사용하지만 (예에서는 항상 이런 식으로 생각할 수 있지만) 음수 인 경우에는 true입니다.
반환 값
x의 부호가 음수이면 0이 아닌 값 (true)입니다. 그렇지 않으면 0 (거짓)입니다.
그런 다음 왼쪽 시프트 ( "<< 1")를 2로 곱하면 양수에 2를, 음수에 0을, 마지막으로 1을 줄이면 요청에 따라 양수와 음수 각각에 대해 1과 -1을 얻습니다. OP.
허용 된 답변의 정수 솔루션은 매우 우아하지만 이중 유형에 대해 NAN을 반환 할 수 없다는 것을 귀찮게 했으므로 약간 수정했습니다.
template <typename T> double sgn(T val) {
return double((T(0) < val) - (val < T(0)))/(val == val);
}
하드 코딩에 반대 부동 소수점 NAN을 반환합니다 NAN부호 비트가 설정되는 원인 일부 구현 에 대한 출력 있도록, val = -NAN그리고 val = NAN당신이 "원하는 경우가는 것은 (상관없이 동일 없습니다 nan이상"출력을 -nan당신이 넣을 수 있습니다 abs(val)반환하기 전에 ...)
당신은 사용할 수 있습니다 boost::math::sign()에서 방법 boost/math/special_functions/sign.hpp부스트를 사용할 수있는 경우입니다.
분기 친화적 인 구현은 다음과 같습니다.
inline int signum(const double x) {
if(x == 0) return 0;
return (1 - (static_cast<int>((*reinterpret_cast<const uint64_t*>(&x)) >> 63) << 1));
}
데이터에 숫자의 절반이 0이 아닌 경우 분기 예측기는 분기 중 하나를 가장 일반적인 것으로 선택합니다. 두 가지 모두 간단한 작업 만 포함합니다.
또는 일부 컴파일러 및 CPU 아키텍처에서 완전히 분기없는 버전이 더 빠를 수 있습니다.
inline int signum(const double x) {
return (x != 0) *
(1 - (static_cast<int>((*reinterpret_cast<const uint64_t*>(&x)) >> 63) << 1));
}
int sign(float n)
{
union { float f; std::uint32_t i; } u { n };
return 1 - ((u.i >> 31) << 1);
}
이 함수는 다음을 가정합니다.
간단하게 할 수있을 때 삼항 연산자와 if-else를 사용하는 이유
#define sgn(x) x==0 ? 0 : x/abs(x)
x == INT_MIN.