1. ホーム
  2. c++

[解決済み] C/C++で標準の符号関数(signum, sgn)はありますか?

2022-03-20 05:28:46

質問

負の数には-1、正の数には+1を返す関数が欲しい。 http://en.wikipedia.org/wiki/Sign_function 自分で書くのは簡単だけど、標準ライブラリのどこかにあるような気がするんだ。

編集部:具体的には、浮動小数点数で動作する関数を探していたんです。

どのように解決するのですか?

タイプセーフのC++版です。

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

メリット

  • Signum (-1、0、1) を実際に実装しています。ここでのcopysignを使った実装は-1か1しか返さないので、signumではありません。また、ここでのいくつかの実装はintではなくfloat(またはT)を返しており、無駄が多いように思われます。
  • int、float、double、unsigned shorts、あるいは integer 0 から構成可能で orderable な任意のカスタム型に対して動作します。
  • 速い! copysign は遅いです。特に、昇格してまた絞り込む必要がある場合は。これは分岐がなく、最適化が可能です。
  • 標準規格に準拠 ビットシフトハックは巧妙ですが、いくつかのビット表現に対してのみ機能し、符号なし型を持っているときには機能しません。適切な場合には、手動で特殊化することも可能である。
  • 正確であること ゼロとの単純な比較は、マシン内部の高精度表現(例えばx87の80ビット)を維持し、ゼロへの早すぎる丸めを回避することができます。

注意点

  • テンプレートなので、状況によってはコンパイルに時間がかかるかもしれません。

  • どうやら、新しく、やや難解で、非常に遅い標準ライブラリ関数を使用することを考える人がいるようだ シグナムを実装していない の方が理解しやすいと思います。

  • < 0 の部分をチェックすると、GCCの -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>());
     }
    
    

    (これは最初の注意点の良い例です)。