C/C++ に標準の符号関数 (signum、sgn) はありますか? 質問する

C/C++ に標準の符号関数 (signum、sgn) はありますか? 質問する

負の数の場合は -1 を返し、正の数の場合は +1 を返す関数が必要です。http://en.wikipedia.org/wiki/Sign_function自分で書くのは簡単ですが、どこかの標準ライブラリにあるべきもののように思えます。

編集: 具体的には、float で動作する関数を探していました。

ベストアンサー1

型安全な C++ バージョン:

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

利点:

  • 実際には signum (-1、0、または 1) を実装します。ここで copysign を使用する実装は、signum ではない -1 または 1 のみを返します。また、ここでの実装の一部は int ではなく float (または T) を返していますが、これは無駄に思えます。
  • int、float、double、unsigned short、または整数 0 から構築可能で順序付け可能な任意のカスタム型で機能します。
  • 高速!copysignは遅い。特に昇格してから再度絞り込む必要がある場合は遅い。これは分岐がなく、優れた最適化を実現している。
  • 標準に準拠しています。ビットシフト ハックは便利ですが、一部のビット表現でしか機能せず、符号なしの型では機能しません。適切な場合は、手動で特殊化して提供できます。
  • 正確です! ゼロとの単純な比較により、マシンの内部の高精度表現 (x87 では 80 ビットなど) が維持され、ゼロへの早すぎる丸めを回避できます。

注意:

  • これはテンプレートなので、状況によってはコンパイルに時間がかかる場合があります。

  • どうやら、signum を実際には実装していない、新しい、やや難解で非常に遅い標準ライブラリ関数を使用する方が理解しやすいと考える人もいるようです。

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

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

おすすめ記事