質問

C ++から、minmaxfminfmaxよりも望ましいですか? 2つの整数を比較するために、それらは基本的に同じ機能を提供しますか?

これらの関数セットのいずれかを使用する傾向がありますか、または独自に作成することを好みますか(おそらく、効率、移植性、柔軟性などを改善するために)?

注:

  1. C ++標準テンプレートライブラリ(STL)は、標準C ++の<=>および<=>関数を宣言しますアルゴリズムヘッダー。

  2. C標準(C99)は、標準C math.h ヘッダー。

事前に感謝します!

役に立ちましたか?

解決

fminおよびfmaxは、特に浮動小数点数で使用するためのものです(そのため<!> quot; f <!> quot;)。 intに使用すると、コンパイラ/プラットフォームによっては、変換、関数呼び出しのオーバーヘッドなどのために、パフォーマンスや精度が低下する場合があります。

std::minおよびstd::maxはテンプレート関数です(ヘッダー <algorithm> <で定義されています/ a>)は、より小(<)演算子を使用して任意の型で機能するため、このような比較を可能にする任意のデータ型を操作できます。 <=>で機能させたくない場合は、独自の比較関数を提供することもできます。

これは、引数のタイプが異なる場合に一致するように引数を明示的に変換する必要があるため、より安全です。コンパイラは、たとえば、64ビットintを誤って64ビットfloatに変換することを許可しません。この理由だけで、テンプレートをデフォルトの選択にする必要があります。 (Matthieu Mへのクレジット<!> amp; bk1e)

floatを使用した場合でも、テンプレートのパフォーマンスは 勝ちます。ソースコードはコンパイル単位の一部であるため、コンパイラには常にテンプレート関数の呼び出しをインライン化するオプションがあります。一方、ライブラリ関数の呼び出しをインライン化することは不可能である場合があります(共有ライブラリ、リンク時最適化の欠如など)。

他のヒント

std::minstd::maxfmin、およびfmaxには重要な違いがあります。

std::min(-0.0,0.0) = -0.0
std::max(-0.0,0.0) = -0.0

whereas

fmin(-0.0, 0.0) = -0.0
fmax(-0.0, 0.0) =  0.0

したがって、x ! = NaN-O3の1-1の代替ではありません。関数std::max(double, double)および-Ofastは可換ではありません。 nanと<=>でdoubleを使用して同じ結果を得るには、引数を交換する必要があります

fmin(-0.0, 0.0) = std::min(-0.0,  0.0)
fmax(-0.0, 0.0) = std::max( 0.0, -0.0)

ただし、これらすべてこの場合、関数はとにかく実装定義されているため、実装方法をテストする必要があります。


別の重要な違いがあります。 <=>の場合:

std::max(Nan,x) = NaN
std::max(x,NaN) = x
std::min(Nan,x) = NaN
std::min(x,NaN) = x

whereas

fmax(Nan,x) = x
fmax(x,NaN) = x
fmin(Nan,x) = x
fmin(x,NaN) = x

<=>は次のコードでエミュレートできます

double myfmax(double x, double y)
{
   // z > nan for z != nan is required by C the standard
   int xnan = isnan(x), ynan = isnan(y);
   if(xnan || ynan) {
        if(xnan && !ynan) return y;
        if(!xnan && ynan) return x;
        return x;
   }
   // +0 > -0 is preferred by C the standard 
   if(x==0 && y==0) {
       int xs = signbit(x), ys = signbit(y);
       if(xs && !ys) return y;
       if(!xs && ys) return x;
       return x;
   }
   return std::max(x,y);
}

これは、<=>が<=>のサブセットであることを示しています。

アセンブリを見ると、Clangは<=>と<=>に組み込みコードを使用しているのに対し、GCCはそれらを数学ライブラリから呼び出しています。 <=>と<=>のclangのアセンブリは次のとおりです

movapd  xmm2, xmm0
cmpunordsd      xmm2, xmm2
movapd  xmm3, xmm2
andpd   xmm3, xmm1
maxsd   xmm1, xmm0
andnpd  xmm2, xmm1
orpd    xmm2, xmm3
movapd  xmm0, xmm2

一方、<=>は単純です

maxsd   xmm0, xmm1

ただし、GCCおよびClangでは、<=> <=>を使用すると単純になります

<*>

したがって、これは<=>が<=>のサブセットであり、<=>または符号付きゼロを持たないより緩やかな浮動小数点モデルを使用する場合、<=>と<=>は同じであることをもう一度示しています。同じ引数が明らかに<=>と<=>に適用されます。

fminとfmaxのポイント全体が欠落しています。 C99に含まれていたため、最新のCPUはネイティブ(SSE読み取り)命令を浮動小数点の最小値と最大値に使用し、テストと分岐(したがって、予測ミスの可能性のある分岐)を回避できます。代わりにstd :: minとstd :: maxを使用するコードを書き直し、代わりに内部ループでminとmaxにSSE組み込み関数を使用しました。スピードアップは著しいものでした。

std :: minおよびstd :: maxはテンプレートです。そのため、float、double、long doubleなど、小なり演算子を提供するさまざまなタイプで使用できます。したがって、一般的なC ++コードを作成する場合は、次のようにします。

template<typename T>
T const& max3(T const& a, T const& b, T const& c)
{
   using std::max;
   return max(max(a,b),c); // non-qualified max allows ADL
}

パフォーマンスに関しては、fminおよびfmaxはC ++のものと異なるとは思いません。

実装で64ビット整数型が提供されている場合、fminまたはfmaxを使用すると、異なる(誤った)答えが返される場合があります。 64ビット整数は倍精度に変換され、(少なくとも通常は)64ビットより小さい仮数を持ちます。このような数値をdoubleに変換すると、最下位ビットの一部が完全に失われる可能性があります/失われます。

これは、実際に異なる2つの数値がdoubleに変換されたときに等しくなる可能性があることを意味し、結果はその誤った数値になり、元の入力のいずれとも必ずしも等しくありません。

C ++を使用している場合は、型固有であるため、C ++のmin / max関数をお勧めします。 fmin / fmaxは、すべてを強制的に浮動小数点に/から変換します。

また、operator <!> lt;を定義している限り、C ++のmin / max関数はユーザー定義型で動作します。それらのタイプに対して。

HTH

お気づきのとおり、fminfmaxはC99で導入されました。標準C ++ライブラリには、std::minおよびstd::max関数がありません。 C99標準ライブラリが(もしあれば)C ++に組み込まれるまで、これらの関数のアプリケーション領域は完全に分離されています。 <!> quot; prefer <!> quot;が必要になる状況はありません。一方を他方に。

C ++でテンプレート化された<=> / <=>を使用し、Cで使用可能なものを使用します。

Richard Cordenが指摘したように、std名前空間で定義されたC ++関数minおよびmaxを使用します。これらは型の安全性を提供し、混合型(つまり、浮動小数点と整数)が望ましくない場合があるものを比較することを回避するのに役立ちます。

使用するC ++ライブラリがマクロとしてmin / maxも定義している場合、競合が発生する可能性があります。この方法でmin / max関数を呼び出す不要なマクロ置換を防ぐことができます(余分な括弧に注意してください):

(std::min)(x, y)
(std::max)(x, y)

これは引数依存ルックアップ(ADL、Koenigルックアップとも呼ばれます)を事実上無効にします。 、ADLに依存したい場合に。

fminとfmaxは、浮動小数点変数とdouble変数専用です。

minおよびmaxは、バイナリ述語を指定すると、任意の型の比較を可能にするテンプレート関数です。また、他のアルゴリズムとともに使用して、複雑な機能を提供することもできます。

std::minおよびstd::maxを使用します。

他のバージョンがより高速である場合、実装によりこれらのオーバーロードが追加され、パフォーマンスと移植性のメリットが得られます。

template <typename T>
T min (T, T) {
  // ... default
}

inline float min (float f1, float f2) {
 return fmin( f1, f2);
}    

ところで、cstdlibには__min__maxがあります。

その他: http://msdn.microsoft.com/zh-cn /library/btkhtd8d.aspx

SSE命令を備えたプロセッサを対象としたC ++実装では、 float std :: min および std :: max の特殊化を提供できませんでした>、 double 、および long double は、 fminf fmin 、および fminl 、それぞれ

特殊化により、浮動小数点型のパフォーマンスが向上しますが、一般テンプレートでは、 fmin のように浮動小数点型を浮動小数点型に強制しようとせずに、非浮動小数点型を処理します。 sおよび fmax esの場合。

intには常にminおよびmaxマクロを使用します。整数値にfminまたはfmaxを使用する理由がわかりません。

最小値と最大値の大きな落とし穴は、たとえそれらがそれらのように見えても、関数ではないことです。次のような場合:

min (10, BigExpensiveFunctionCall())

マクロの実装によっては、その関数呼び出しが2回呼び出される場合があります。そのため、私の組織では、リテラルまたは変数でないものでminまたはmaxを呼び出さないようにすることをお勧めします。

符号付き整数と符号なし整数を比較する場合、fminfmax

fminlfmaxlが優先される可能性があります-符号付きと符号なしの数値の範囲全体が、整数範囲とプロモーションについて心配する必要があります。

unsigned int x = 4000000000;
int y = -1;

int z = min(x, y);
z = (int)fmin(x, y);
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top