Domanda

Dal C++, lo sono min E max preferibile sopra fmin E fmax?Per confrontare due numeri interi, forniscono sostanzialmente la stessa funzionalità?

Tendi a utilizzare uno di questi set di funzioni o preferisci scriverne uno tuo (magari per migliorare l'efficienza, la portabilità, la flessibilità, ecc.)?

Appunti:

  1. La libreria di modelli standard (STL) C++ dichiara il file min E max funzioni nel C++ standard algoritmo intestazione.

  2. Lo standard C (C99) fornisce il fmin E fmax funzione nello standard C matematica.h intestazione.

Grazie in anticipo!

È stato utile?

Soluzione

fmin e fmax sono specifici per l'uso con numeri in virgola mobile (quindi " f "). Se lo usi per gli inte, potresti subire perdite di prestazioni o precisione dovute alla conversione, al sovraccarico di chiamate di funzione, ecc. A seconda del tuo compilatore / piattaforma.

std::min e std::max sono funzioni modello (definite nell'intestazione <algorithm> ) che funzionano su qualsiasi tipo con un operatore minore di (<), quindi possono operare su qualsiasi tipo di dati che consenta tale confronto. Puoi anche fornire la tua funzione di confronto se non vuoi che funzioni <=>.

Questo è più sicuro poiché devi convertire esplicitamente gli argomenti in modo che corrispondano quando hanno tipi diversi. Il compilatore non ti consente di convertire accidentalmente un int a 64 bit in un float a 64 bit, ad esempio. Questo motivo da solo dovrebbe rendere i modelli la scelta predefinita. (Ringraziamo Matthieu M & Amp; bk1e)

Anche se usato con float, il modello may può vincere in termini di prestazioni. Un compilatore ha sempre la possibilità di incorporare le chiamate alle funzioni del modello poiché il codice sorgente fa parte dell'unità di compilazione. A volte è impossibile incorporare una chiamata a una funzione di libreria, d'altra parte (librerie condivise, assenza di ottimizzazione del tempo di collegamento, ecc.)

Altri suggerimenti

Esiste una differenza importante tra std::min, std::max e fmin e fmax.

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

, mentre

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

Quindi x ! = NaN non è un sostituto 1-1 per -O3. Le funzioni std::max(double, double) e -Ofast non sono commutative. Per ottenere lo stesso risultato con i doppi con nan e <=> è necessario scambiare gli argomenti

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

Ma per quanto posso dire tutti questi le funzioni sono comunque definite in questo caso quindi per essere sicuri al 100% devi testare come sono implementate.


C'è un'altra differenza importante. Per <=>:

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

, mentre

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

<=> può essere emulato con il seguente codice

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

Questo mostra che <=> è un sottoinsieme di <=>.

Guardando l'assemblaggio si vede che Clang usa il codice incorporato per <=> e <=> mentre GCC li chiama da una libreria matematica. L'assembly per clang per <=> con <=> è

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

mentre per <=> è semplicemente

maxsd   xmm0, xmm1

Tuttavia, per GCC e Clang l'utilizzo di <=> <=> diventa semplicemente

<*>

Quindi, ciò dimostra ancora una volta che <=> è un sottoinsieme di <=> e che quando si utilizza un modello a virgola mobile più sciolto che non ha <=> o zero con segno, allora <=> e <=> sono gli stessi . Lo stesso argomento ovviamente si applica a <=> e <=>.

Ti manca l'intero punto di fmin e fmax. È stato incluso in C99 in modo che le CPU moderne potessero utilizzare le loro istruzioni native (leggi SSE) per il virgola mobile min e max ed evitare un test e una diramazione (e quindi una diramazione probabilmente errata). Ho riscritto il codice che utilizzava std :: min e std :: max per usare intrinsecamente SSE per min e max nei loop interni e l'accelerazione era significativa.

std :: min e std :: max sono modelli. Quindi, possono essere utilizzati su una varietà di tipi che forniscono meno dell'operatore, inclusi galleggianti, doppi, doppi lunghi. Quindi, se volessi scrivere un codice C ++ generico, faresti qualcosa del genere:

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
}

Per quanto riguarda le prestazioni, non credo che fmin e fmax differiscano dalle loro controparti C ++.

Se l'implementazione fornisce un tipo intero a 64 bit, è possibile ottenere una risposta diversa (errata) utilizzando fmin o fmax. I tuoi numeri interi a 64 bit verranno convertiti in doppi, che avranno (almeno di solito) un significato minore di 64 bit. Quando converti un tale numero in doppio, alcuni dei bit meno significativi possono / andranno persi completamente.

Ciò significa che due numeri che erano davvero diversi potrebbero finire uguali quando convertiti in doppio - e il risultato sarà quel numero errato, che non è necessariamente uguale a nessuno degli input originali.

Preferirei le funzioni min/max C++, se si utilizza C++, perché sono specifiche del tipo.fmin/fmax forzerà la conversione di tutto in/da virgola mobile.

Inoltre, le funzioni min/max C++ funzioneranno con i tipi definiti dall'utente purché sia ​​stato definito operator< per tali tipi.

HTH

Come hai notato te stesso, fmin e fmax sono stati introdotti in C99. La libreria C ++ standard non ha std::min e std::max funzioni. Fino a quando la libreria standard C99 non viene incorporata in C ++ (se mai), le aree di applicazione di queste funzioni sono separate in modo chiaro. Non c'è nessuna situazione in cui potresti dover & Quot; preferisci & Quot; uno sopra l'altro.

Devi solo usare il template <=> / <=> in C ++ e usare tutto ciò che è disponibile in C.

Come ha sottolineato Richard Corden, utilizzare le funzioni C ++ min e max definite nello spazio dei nomi std. Forniscono la sicurezza dei tipi e aiutano a evitare il confronto dei tipi misti (cioè virgola mobile vs intero) ciò che a volte può essere indesiderabile.

Se trovi che la libreria C ++ che usi definisce min / max anche come macro, può causare conflitti, quindi puoi impedire la sostituzione indesiderata di macro chiamando le funzioni min / max in questo modo (nota tra parentesi extra):

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

Ricorda, questo disabiliterà efficacemente Ricerca dipendente dall'argomento (ADL, chiamata anche ricerca Koenig) , nel caso in cui si desideri fare affidamento su ADL.

fmin e fmax sono solo per virgola mobile e doppie variabili.

min e max sono funzioni modello che consentono il confronto di qualsiasi tipo, dato un predicato binario. Possono anche essere utilizzati con altri algoritmi per fornire funzionalità complesse.

Usa std::min e std::max.

Se le altre versioni sono più veloci, l'implementazione può aggiungere sovraccarichi per queste e otterrai il vantaggio di prestazioni e portabilità:

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

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

A proposito, in cstdlib ci sono __min e __max puoi usare.

Per ulteriori informazioni: http://msdn.microsoft.com/zh-cn /library/btkhtd8d.aspx

Un'implementazione C ++ destinata ai processori con istruzioni SSE non potrebbe fornire specializzazioni di std :: min e std :: max per i tipi float , doppio e doppio lungo che equivalgono a fminf , fmin e fminl , rispettivamente?

Le specializzazioni fornirebbero prestazioni migliori per i tipi a virgola mobile mentre il modello generale gestirà i tipi a virgola mobile senza tentare di forzare i tipi a virgola mobile in tipi a virgola mobile in questo modo il fmin se fmax es.

Uso sempre le macro min e max per gli ints. Non sono sicuro del motivo per cui qualcuno dovrebbe usare fmin o fmax per valori interi.

Il grande gotcha con min e max è che non sono funzioni, anche se sembrano simili a loro. Se fai qualcosa del tipo:

min (10, BigExpensiveFunctionCall())

Quella chiamata di funzione può essere chiamata due volte a seconda dell'implementazione della macro. In quanto tale, è consigliabile nella mia organizzazione non chiamare mai min o max con cose che non sono letterali o variabili.

fmin e fmax, di fminl e fmaxl potrebbero essere preferiti quando si confrontano numeri interi con o senza segno - è possibile trarre vantaggio dal fatto che l'intera gamma di numeri con e senza segno e non devi preoccuparti di intervalli interi e promozioni.

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

int z = min(x, y);
z = (int)fmin(x, y);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top