web-dev-qa-db-ja.com

C ++でのminおよびmax関数の使用

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

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

注:

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

  2. C標準(C99)は、標準C math.h ヘッダーでfminおよびfmax関数を提供します。

前もって感謝します!

64
bporter

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

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

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

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

100
Cogwheel

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

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

一方

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

したがって、std::minfminの1-1の代替ではありません。関数std::minおよびstd::maxは可換ではありません。 fminfmaxのdoubleで同じ結果を得るには、引数を交換する必要があります

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

しかし、私が知る限り、 これらの関数はすべて、この場合とにかく定義された実装です ですから、それらがどのように実装されているかを100%確認する必要があります。


別の重要な違いがあります。 x ! = NaNの場合:

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

一方

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

fmaxは次のコードでエミュレートできます

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

これは、std::maxfmaxのサブセットであることを示しています。

アセンブリを見ると、Clangがfmaxおよびfminに組み込みコードを使用しているのに対し、GCCはそれらを数学ライブラリから呼び出していることがわかります。 -O3を含むfmaxのc​​langのアセンブリは

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

一方、std::max(double, double)の場合は単に

maxsd   xmm0, xmm1

ただし、GCCおよびClangの場合、-Ofastfmaxを使用すると、単純になります

maxsd   xmm0, xmm1

したがって、これはstd::maxfmaxのサブセットであり、nanまたは符号付きゼロを持たない緩い浮動小数点モデルを使用する場合、fmaxおよびstd::maxは同じです。同じ引数がfminstd::minにも明らかに適用されます。

30
Z boson

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

16
J Ridges

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
}

パフォーマンスに関しては、fminfmaxはC++のものと異なるとは思わない。

6
sellibitze

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

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

6
Jerry Coffin

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

また、C++のmin/max関数は、ユーザー定義型に対してoperator <を定義している限り、それらの型で機能します。

HTH

4
Eric Melski

すでに述べたように、C99ではfminfmaxが導入されました。標準C++ライブラリには、fminおよびfmax関数がありません。 C99標準ライブラリがC++に組み込まれるまで(もしあれば)、これらの関数のアプリケーション領域は完全に分離されます。どちらかを「優先」しなければならない状況はありません。

C++ではテンプレート化されたstd::min/std::maxを使用し、Cで使用可能なものはすべて使用します。

2
AnT

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

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

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

ADLに依存したい場合は、これにより実質的に Argument Dependent Lookup (ADL、Koenigルックアップとも呼ばれます)が無効になります。

2
mloskot

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

他のバージョンがより高速である場合、実装はこれらのオーバーロードを追加でき、パフォーマンスと移植性の利点が得られます。

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

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

SSE命令を持つプロセッサを対象としたC++実装はできませんでした。std :: minおよびstd :: maxタイプfloatdouble、およびlong doublefminffmin、およびfminl、それぞれ?

特殊化により、浮動小数点型のパフォーマンスが向上しますが、一般的なテンプレートは、浮動小数点型をfminsおよびfmaxesになります。

1
user3405743

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

詳細: http://msdn.Microsoft.com/zh-cn/library/btkhtd8d.aspx

1
Justme0

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

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

1
Marcin

fminfmaxfminlfmaxlは、符号付き整数と符号なし整数を比較するときに優先される可能性があります。整数の範囲とプロモーションについて心配する必要はありません。

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

int z = min(x, y);
z = (int)fmin(x, y);
0
Eclipse

Intには常にminおよびmaxマクロを使用します。整数値にfminまたはfmaxを使用する理由がわからない。

Minとmaxの大きな落とし穴は、たとえそれらが見た目であっても、関数ではないということです。次のようなことをする場合:

min (10, BigExpensiveFunctionCall())

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

0
popester