Lo standard C ++ 03 si basa sullo standard C90 per quello che lo standard chiama la libreria C standard che è coperta nella bozza della norma C ++ 03 (la bozza più vicina alla bozza della norma C ++ 03 è N1804 ) 1.2
Riferimenti normativi :
La libreria descritta nella clausola 7 della ISO / IEC 9899: 1990 e nella clausola 7 della ISO / IEC 9899 / Amd.1: 1995 è di seguito denominata Standard C Library. 1)
Se andiamo alla documentazione C per round, lround, llround su cppreference possiamo vedere che round e le relative funzioni fanno parte di C99 e quindi non saranno disponibili in C ++ 03 o precedenti.
In C ++ 11 questo cambia poiché C ++ 11 si basa sulla bozza standard C99 per la libreria standard C e quindi fornisce std :: round e per i tipi di ritorno integrale std :: lround, std :: llround :
#include <iostream>
#include <cmath>
int main()
{
std::cout << std::round( 0.4 ) << " " << std::lround( 0.4 ) << " " << std::llround( 0.4 ) << std::endl ;
std::cout << std::round( 0.5 ) << " " << std::lround( 0.5 ) << " " << std::llround( 0.5 ) << std::endl ;
std::cout << std::round( 0.6 ) << " " << std::lround( 0.6 ) << " " << std::llround( 0.6 ) << std::endl ;
}
Un'altra opzione anche da C99 sarebbe std :: trunc che:
Calcola il numero intero più vicino non più grande dell'arg.
#include <iostream>
#include <cmath>
int main()
{
std::cout << std::trunc( 0.4 ) << std::endl ;
std::cout << std::trunc( 0.9 ) << std::endl ;
std::cout << std::trunc( 1.1 ) << std::endl ;
}
Se è necessario supportare applicazioni non C ++ 11, la soluzione migliore sarebbe quella di utilizzare boost round, iround, lround, llround o boost trunc .
Rotolare la tua versione di round è difficile
Arrotolare il tuo probabilmente non vale la pena più difficile di quanto sembri: arrotondare float al numero intero più vicino, parte 1 , arrotondare float al numero intero più vicino, parte 2 e arrotondare float al numero intero più vicino, parte 3 spiega:
Ad esempio, un roll comune che l'implementazione utilizza std::floor
e aggiunge 0.5
non funziona per tutti gli input:
double myround(double d)
{
return std::floor(d + 0.5);
}
Un input per cui questo fallirà è 0.49999999999999994
, ( vederlo dal vivo ).
Un'altra implementazione comune prevede il cast di un tipo a virgola mobile in un tipo integrale, che può invocare un comportamento indefinito nel caso in cui la parte integrale non possa essere rappresentata nel tipo di destinazione. Possiamo vederlo dalla bozza della sezione standard C ++ 4.9
Conversioni floating-integral che dice ( enfasi mia ):
Un valore di un tipo a virgola mobile può essere convertito in un valore di un tipo intero. La conversione tronca; cioè, la parte frazionaria viene scartata. Il comportamento non è definito se il valore troncato non può essere rappresentato nel tipo di destinazione. [...]
Per esempio:
float myround(float f)
{
return static_cast<float>( static_cast<unsigned int>( f ) ) ;
}
Data std::numeric_limits<unsigned int>::max()
è 4294967295
quindi la seguente chiamata:
myround( 4294967296.5f )
causerà overflow, ( vederlo dal vivo ).
Possiamo vedere quanto sia davvero difficile osservando questa risposta al modo conciso di implementare round () in C? quale riferimento alla versione newlibs del galleggiante di precisione singolo rotondo. È una funzione molto lunga per qualcosa che sembra semplice. Sembra improbabile che chiunque non abbia una conoscenza intima delle implementazioni in virgola mobile possa implementare correttamente questa funzione:
float roundf(x)
{
int signbit;
__uint32_t w;
/* Most significant word, least significant word. */
int exponent_less_127;
GET_FLOAT_WORD(w, x);
/* Extract sign bit. */
signbit = w & 0x80000000;
/* Extract exponent field. */
exponent_less_127 = (int)((w & 0x7f800000) >> 23) - 127;
if (exponent_less_127 < 23)
{
if (exponent_less_127 < 0)
{
w &= 0x80000000;
if (exponent_less_127 == -1)
/* Result is +1.0 or -1.0. */
w |= ((__uint32_t)127 << 23);
}
else
{
unsigned int exponent_mask = 0x007fffff >> exponent_less_127;
if ((w & exponent_mask) == 0)
/* x has an integral value. */
return x;
w += 0x00400000 >> exponent_less_127;
w &= ~exponent_mask;
}
}
else
{
if (exponent_less_127 == 128)
/* x is NaN or infinite. */
return x + x;
else
return x;
}
SET_FLOAT_WORD(x, w);
return x;
}
D'altra parte, se nessuna delle altre soluzioni è utilizzabile, newlib potrebbe potenzialmente essere un'opzione poiché è un'implementazione ben collaudata.
std::cout << std::fixed << std::setprecision(0) << -0.9
, per esempio.