programing

C/C++에 표준 기호 함수(signum, sgn)가 있습니까?

prostudy 2022. 8. 25. 21:31
반응형

C/C++에 표준 기호 함수(signum, sgn)가 있습니까?

음수는 -1, 양수는 +1을 반환하는 함수를 원합니다.http://en.wikipedia.org/wiki/Sign_function 내 것을 쓰는 것은 충분히 쉽지만, 어딘가 표준 도서관에 있어야 할 것 같다.

편집: 구체적으로는 플로트에서 기능하는 기능을 찾고 있었습니다.

타입 세이프 C++ 버전:

template <typename T> int sgn(T val) {
    return (T(0) < val) - (val < T(0));
}

이점:

  • 실제로 시그넘(-1, 0 또는 1)을 실장합니다.여기서 copysign을 사용한 구현에서는 -1 또는 1만 반환되며 이는 시그넘이 아닙니다.또한 일부 구현에서는 int가 아닌 float(또는 T)를 반환하고 있습니다.이것은 낭비라고 생각됩니다.
  • int, floats, double, unsigned short 또는 정수 0에서 구성 가능하며 오더 가능한 모든 커스텀유형에 대해 기능합니다.
  • 빨리!copysign특히 프로모션을 하고 다시 범위를 좁혀야 할 경우 속도가 느립니다. 되어 있습니다.
  • 규격 준거!비트 시프트 해킹은 깔끔하지만 일부 비트 표현에서만 작동하며 서명되지 않은 타입의 경우 작동하지 않습니다.적절한 경우 수동 전문화로 제공될 수 있습니다.
  • 정확해!0과의 간단한 비교는 기계의 내부 정밀도 표현(예: x87의 80비트)을 유지할 수 있으며, 0으로의 조기 라운딩을 방지할 수 있습니다.

경고:

  • 템플릿이기 때문에 컴파일하는 데 시간이 더 걸릴 수 있습니다.

  • 분명히 어떤 사람들은 시그넘조차 실제로 구현하지 않는 새롭고 다소 난해하며 매우 느린 표준 라이브러리 기능을 사용하는 것이 더 이해할 수 있다고 생각한다.

  • < 0GCC를 .-Wtype-limits경고는 서명되지 않은 유형에 대해 인스턴스화되었을 때 발생합니다.일부 오버로드를 사용하면 이를 방지할 수 있습니다.

     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>());
     }
    

    (이것은 첫 번째 경고의 좋은 예입니다).

나는 그것의 표준 기능을 모른다.여기 이 글을 쓰는 재미있는 방법이 있습니다.

(x > 0) - (x < 0)

보다 읽기 쉬운 방법은 다음과 같습니다.

if (x > 0) return 1;
if (x < 0) return -1;
return 0;

3진 연산자가 필요한 경우 다음을 수행할 수 있습니다.

(x > 0) ? 1 : ((x < 0) ? -1 : 0)

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(1.0, arg)에는 True Sign 함수가 있습니다.이것은 표준의 일부일 가능성이 있습니다.

    #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);

http://www.boost.org/doc/libs/1_47_0/libs/math/doc/sf_and_dist/html/math_toolkit/utils/sign_functions.html

C/C++에 표준 기호 함수(signum, sgn)가 있습니까?

네, 정의에 따라 다르죠.

에는 C99가 되어 있습니다.signbit()로 작성하다<math.h>

int signbit)x
signbitnegative인 에만 제로 이외의 을 반환합니다.macro는 인수값의 가 negative인 에만 0을 반환한다 712.6C11 7.12.3.6.


하지만 OP는 조금 다른 것을 원한다.

음수일 경우 -1을 반환하고 양수일 경우 +1을 반환하는 함수를 원합니다. ... 플로트에서 작동하는 함수입니다.

#define signbit_p1_or_n1(x)  ((signbit(x) ?  -1 : 1)

상세:

OP의 .x = 0.0, -0.0, +NaN, -NaN.

고전적인 반품+1x>0,-1x<0 ★★★★★★★★★★★★★★★★★」0x==0.

이 이미 , , 다루지 않는다.x = -0.0, +NaN, -NaN많은 경우 NaN(Not-a-Numbers)과 -0.0이 없는 정수 시점용으로 설계되어 있습니다.

은 '아까보다'와 같은 기능을 .signnum_typical()온에 -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;
}

츠키다온에 -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;
}

원래 포스터의 질문에 대한 대답은 '아니오'인 것 같다.표준 C++는 없습니다.sgn★★★★★★ 。

일반적으로 C/C++에는 표준 시그넘 함수가 없으며 이러한 기본 함수의 결여는 이러한 언어에 대해 많은 것을 말해줍니다.

이와는 별도로, 이러한 기능을 정의하는 올바른 접근법에 대한 두 가지 견해는 모두 옳다고 생각합니다.또, 그 「논란」은, 다음의 2개의 중요한 경고를 고려하면, 실제로는 논할 수 없는 것입니다.

  • signum 함수는 항상 피연산자의 유형을 반환해야 합니다.abs()함수, 왜냐하면 시그넘은 보통 후자가 어떻게든 처리된 후에 절대값을 가진 곱셈에 사용되기 때문이다.따라서 signum의 주요 사용 사례는 비교가 아니라 산술이며, signum은 값비싼 정수-to-from-floating-point 변환을 수반하지 않아야 합니다.

  • 부동소수점 유형에는 정확한 제로 값이 없습니다.+0.0은 "최종적으로 0보다 높음"으로, -0.0은 "최종적으로 0보다 낮음"으로 해석할 수 있습니다.으로 두에 대해 해야 하는 것이고, 은 0과 같은 표현도 있어야 . 그리고 다음과 같은 식입니다.x == 0.0위험할 수 있습니다.

만, 가장 은 역시 합니다.(x > 0) - (x < 0)표현은 브랜치프리 방식으로 번역해야 하며 기본 연산은 3개뿐입니다.를 가장 잘 하고 C11을 합니다.define _Generic이러한 기능을 공통 이름에 매핑합니다.

부동소수점 값은 C11을 기반으로 한 인라인 함수라고 생각합니다.copysignf(1.0f, x),copysign(1.0, x),그리고.copysignl(1.0l, x)이는 단순히 분기 없이 사용할 가능성이 높고 정수의 결과를 부동소수점 값으로 되돌릴 필요가 없기 때문입니다.부동소수점 제로 값의 특성, 처리 시간 고려 사항 및 부동소수점 산술에서 정확한 -1/+1 기호를 받는 것이 종종 0 값에도 매우 유용하기 때문에 기호의 부동소수점 구현이 0을 반환하지 않는다는 점을 유의해야 합니다.

부호를 테스트할 경우 signbit를 사용합니다(인수에 음의 부호가 있으면 true를 반환합니다).특히 -1 또는 +1을 반환하고 싶은 이유는 확실하지 않습니다.복사인이 더 편리하지만 마이너스0을 부분적으로 지원하는 일부 플랫폼에서는 마이너스0을 반환하는 +1을 반환하는 것처럼 들립니다.

오래된 질문이지만, 지금은 이런 종류의 원하는 기능이 있습니다.not, left shift, dec로 된 포장지를 추가했습니다.

C99의 시그니처 비트에 근거해 래퍼 기능을 사용하면, 필요한 동작을 정확하게 얻을 수 있습니다(아래의 코드 참조).

x 기호가 음수인지 여부를 반환합니다.
이는 무한소, NaN 및 0에도 적용할 수 있습니다(0이 부호 없는 경우 양수로 간주됩니다).

#include <math.h>

int signValue(float a) {
    return ((!signbit(a)) << 1) - 1;
}

NB: signbit의 반환값이 1로 지정되지 않았지만("!") 음수에 대해서는 true로 지정되어 있기 때문에 피연산자를 사용하지 않습니다.

반환값
x 기호가 음수이면 0이 아닌 값(true)이고, 그렇지 않으면 0(false)입니다.

그런 다음 왼쪽 시프트("< 1")에 2를 곱하면, OP가 요청한 양수와 음수에 대해 각각 1과 -1을 얻기 위해 마지막으로 1을 감소시킵니다.

최고 등급의 솔루션을 포함한 위의 솔루션보다 고속화:

(x < 0) ? -1 : (x > 0)

다음 오버로드가 있는 허용 응답은 실제로 -Wtype-limits를 트리거하지 않습니다.단, 사용되지 않는 인수의 경고는 트리거됩니다.is_signed변수).이러한 문제를 피하기 위해 두 번째 인수에 다음과 같은 이름을 붙이지 마십시오.

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에서는 경고를 트리거하지 않습니다.

사용할 수 있습니다.boost::math::sign()로부터의 방법.boost/math/special_functions/sign.hpp부스트를 사용할 수 있는 경우.

주제에서 벗어나긴 하지만, 나는 이것을 사용한다:

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) );
}

대.

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);
}

C를 넛셸로 복사하면 copysign이라는 표준 함수의 존재를 알 수 있습니다.copysign(1.0, -2.0)은 -1.0을 반환하고 copysign(1.0, 2.0)은 +1.0을 반환하는 것으로 보입니다.

꽤 가까웠죠?

가지를 치지 않고 할 수 있는 방법이 있는데 별로 예쁘지 않아요.

sign = -(int)((unsigned int)((int)v) >> (sizeof(int) * CHAR_BIT - 1));

http://graphics.stanford.edu/ ~ seander / seagnacks . http:/http://graphics.stanford.edu/

그 페이지에는 다른 흥미롭고, 지나치게 똑똑한 것들이 많이 있어.

아니요, matlab처럼 c++에는 없습니다.나는 이것을 위해 내 프로그램에서 매크로를 사용한다.

#define sign(a) ( ( (a) < 0 )  ?  -1   : ( (a) > 0 ) )
int sign(float n)
{     
  union { float f; std::uint32_t i; } u { n };
  return 1 - ((u.i >> 31) << 1);
}

이 함수는 다음과 같이 가정합니다.

  • 부동소수점 번호의 binary32 표현
  • 이름 있는 유니언을 사용할 때 엄밀한 에일리어싱 규칙에 대한 예외를 두는 컴파일러
double signof(double a) { return (a == 0) ? 0 : (a<0 ? -1 : 1); }

이 작업을 간단히 수행할 수 있는데 3진 연산자와 if-else를 사용하는 이유는 무엇입니까?

#define sgn(x) x==0 ? 0 : x/abs(x)

수용된 답변의 정수 솔루션은 매우 우아하지만, 더블 타입의 경우 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)반환 전...)

브런치에 편리한 실장은 다음과 같습니다.

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));
}

이것은 IEEE 754의 2배 정밀도의 바이너리 부동소수점 형식(binary 64)에 유효합니다.

언급URL : https://stackoverflow.com/questions/1903954/is-there-a-standard-sign-function-signum-sgn-in-c-c

반응형