음수의 경우 -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 사이에서 앞뒤로 이동하는 것을 포함하여 더 많은 명령어).
copysign
int를 호출 하면 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()
은 +1
on x>0
, -1
on x<0
및 0
on으로 돌아갑니다 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);
입니다.
v
int보다 넓지 않은 정수 타입 임을 의미합니다.
일반적으로 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
.