round () per float in C ++

Ho bisogno di una semplice funzione di arrotondamento in virgola mobile, quindi:

double round(double); round(0.1) = 0 round(-0.1) = 0 round(-0.9) = -1 

Posso trovare ceil() e floor() in math.h – ma non round() .

È presente nella libreria standard di C ++ con un altro nome, o manca?

Non c’è round () nella libreria standard C ++ 98. Puoi scriverne uno tu stesso. Quanto segue è un’implementazione del mezzo round-up :

 double round(double d) { return floor(d + 0.5); } 

Il motivo probabile per cui non esiste una funzione circolare nella libreria standard C ++ 98 è che può essere implementato in modi diversi. Quanto sopra è un modo comune, ma ce ne sono altri come il round-to-even , che è meno di parte e generalmente meglio se stai andando a fare un sacco di arrotondamenti; è però un po ‘più complesso da implementare.

Boost offre un semplice set di funzioni di arrotondamento.

 #include  double a = boost::math::round(1.5); // Yields 2.0 int b = boost::math::iround(1.5); // Yields 2 as an integer 

Per ulteriori informazioni, consultare la documentazione di Boost .

Modifica : dal C ++ 11, ci sono std::round , std::lround e std::llround .

Lo standard C ++ 03 si basa sullo standard C90 per ciò che lo standard chiama la libreria standard C, che è trattato nella bozza dello standard C ++ 03 (la bozza più vicina disponibile pubblicamente standard a C ++ 03 è N1804 ) sezione 1.2 Riferimenti normativi :

La libreria descritta nella clausola 7 della ISO / IEC 9899: 1990 e la clausola 7 della ISO / IEC 9899 / Amd.1: 1995 è in appresso denominata Libreria standard C. 1)

Se andiamo alla documentazione C per round, lround, llround su cppreference possiamo vedere che le funzioni round e correlate fanno parte di C99 e quindi non saranno disponibili in C ++ 03 o precedenti.

In C ++ 11 questo cambiamento dal C ++ 11 si basa sullo standard di bozza C99 per la libreria standard C e quindi fornisce std :: round e per tipi di ritorno integrali std :: lround, std :: llround :

 #include  #include  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 con un valore non maggiore di arg.

 #include  #include  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 hai bisogno di supportare applicazioni non C ++ 11 la cosa migliore da fare sarebbe usare boost round, iround, lround, llround o boost trunc .

Tirare la propria versione di round è difficile

Rollare il proprio non è probabilmente lo sforzo più difficile di quanto sembri: arrotondamento al numero intero più vicino, parte 1 , Arrotondamento al numero intero più vicino, parte 2 e Arrotondamento al numero intero più vicino, la parte 3 spiega:

Ad esempio un roll comune dell'implementazione usando std::floor e l'aggiunta di 0.5 non funziona per tutti gli input:

 double myround(double d) { return std::floor(d + 0.5); } 

Un input che fallirà per è 0.49999999999999994 , ( vederlo dal vivo ).

Un'altra implementazione comune prevede il casting di un tipo a virgola mobile su un tipo integrale, che può richiamare un comportamento non definito nel caso in cui la parte integrale non possa essere rappresentata nel tipo di destinazione. Possiamo vedere questo dalla bozza della sezione standard C ++ 4.9 Conversioni integrale-floating che dice ( enfasi mia ):

Un valore di un valore in 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( static_cast( f ) ) ; } 

Dato std::numeric_limits::max() è 4294967295 quindi la seguente chiamata:

 myround( 4294967296.5f ) 

causerà overflow, ( vederlo dal vivo ).

Possiamo vedere quanto sia davvero difficile guardare questa risposta al modo Conciso per implementare round () in C? che fa riferimento alla versione newlibs del round float a precisione singola. È una funzione molto lunga per qualcosa che sembra semplice. Sembra improbabile che chiunque non abbia una conoscenza approfondita 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'altro canto, se nessuna delle altre soluzioni è utilizzabile, newlib potrebbe potenzialmente essere un'opzione poiché è un'implementazione ben testata.

Può essere interessante notare che se si desidera ottenere un risultato intero dall’arrotondamento, non è necessario passarlo attraverso il ceil o il pavimento. Vale a dire,

 int round_int( double r ) { return (r > 0.0) ? (r + 0.5) : (r - 0.5); } 

È disponibile dal C ++ 11 in cmath (secondo http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf )

 #include  #include  int main(int argc, char** argv) { std::cout << "round(0.5):\t" << round(0.5) << std::endl; std::cout << "round(-0.5):\t" << round(-0.5) << std::endl; std::cout << "round(1.4):\t" << round(1.4) << std::endl; std::cout << "round(-1.4):\t" << round(-1.4) << std::endl; std::cout << "round(1.6):\t" << round(1.6) << std::endl; std::cout << "round(-1.6):\t" << round(-1.6) << std::endl; return 0; } 

Produzione:

 round(0.5): 1 round(-0.5): -1 round(1.4): 1 round(-1.4): -1 round(1.6): 2 round(-1.6): -2 

Di solito è implementato come floor(value + 0.5) .

Modifica: probabilmente non viene chiamato round poiché ci sono almeno tre algoritmi di arrotondamento che conosco: round to zero, round al più vicino intero e arrotondamento del banchiere. Stai chiedendo il numero intero più vicino.

Ci sono 2 problemi che stiamo guardando:

  1. conversioni di arrotondamento
  2. digitare conversione.

Le conversioni di arrotondamento si riferiscono all’arrotondamento ± float / double al piano più vicino / ceil float / double. Potrebbe essere il tuo problema finisce qui. Tuttavia, se si prevede di restituire Int / Long, è necessario eseguire la conversione del tipo, e quindi il problema “Overflow” potrebbe colpire la soluzione. SO, fai un controllo per errore nella tua funzione

 long round(double x) { assert(x >= LONG_MIN-0.5); assert(x <= LONG_MAX+0.5); if (x >= 0) return (long) (x+0.5); return (long) (x-0.5); } #define round(x) ((x) < LONG_MIN-0.5 || (x) > LONG_MAX+0.5 ?\ error() : ((x)>=0?(long)((x)+0.5):(long)((x)-0.5)) 

da: http://www.cs.tut.fi/~jkorpela/round.html

In Boost è anche implementato un certo tipo di arrotondamento:

 #include  #include  template T round2(const S& x) { typedef boost::numeric::conversion_traits Traits; typedef boost::numeric::def_overflow_handler OverflowHandler; typedef boost::numeric::RoundEven Rounder; typedef boost::numeric::converter Converter; return Converter::convert(x); } int main() { std::cout << round2(0.1) << ' ' << round2(-0.1) << ' ' << round2(-0.9) << std::endl; } 

Si noti che questo funziona solo se si esegue una conversione da intero.

È ansible arrotondare alla precisione delle cifre con:

 double round( double x ) { const double sd = 1000; //for accuracy to 3 decimal places return int(x*sd + (x<0? -0.5 : 0.5))/sd; } 

Se alla fine vuoi convertire il double output della tua funzione round() in un int , allora le soluzioni accettate di questa domanda avranno un aspetto simile:

 int roundint(double r) { return (int)((r > 0.0) ? floor(r + 0.5) : ceil(r - 0.5)); } 

Questo orologio si aggira intorno a 8,88 ns sulla mia macchina quando viene passato in valori uniformsmente casuali.

Il sotto è funzionalmente equivalente, per quanto posso dire, ma orologi a 2,48 ns sulla mia macchina, per un significativo vantaggio prestazionale:

 int roundint (double r) { int tmp = static_cast (r); tmp += (r-tmp>=.5) - (r-tmp<=-.5); return tmp; } 

Tra le ragioni per le migliori prestazioni c'è la ramificazione saltata.

Attenzione al floor(x+0.5) . Ecco cosa può accadere per i numeri dispari nell’intervallo [2 ^ 52,2 ^ 53]:

 -bash-3.2$ cat >test-round.c < #include  int main() { double x=5000000000000001.0; double y=round(x); double z=floor(x+0.5); printf(" x =%f\n",x); printf("round(x) =%f\n",y); printf("floor(x+0.5)=%f\n",z); return 0; } END -bash-3.2$ gcc test-round.c -bash-3.2$ ./a.out x =5000000000000001.000000 round(x) =5000000000000001.000000 floor(x+0.5)=5000000000000002.000000 

Questo è http://bugs.squeak.org/view.php?id=7134 . Usa una soluzione come quella di @konik.

La mia versione robusta sarebbe qualcosa del tipo:

 double round(double x) { double truncated,roundedFraction; double fraction = modf(x, &truncated); modf(2.0*fraction, &roundedFraction); return truncated + roundedFraction; } 

Un altro motivo per evitare floor (x + 0.5) è dato qui .

Non è necessario implementare nulla, quindi non sono sicuro del perché così tante risposte implichino definizioni, funzioni o metodi.

Nel C99

Abbiamo il seguente ede l’intestazione per i macro di tipo generico.

 #include  double round (double x); float roundf (float x); long double roundl (long double x); 

Se non riesci a compilarlo, probabilmente hai dimenticato la libreria matematica. Un comando simile a questo funziona su ogni compilatore C che ho (diversi).

 gcc -lm -std=c99 ... 

In C ++ 11

Abbiamo i seguenti e sovraccarichi aggiuntivi in ​​#include che si basano su un punto di virgola mobile a precisione doppia IEEE.

 #include  double round (double x); float round (float x); long double round (long double x); double round (T x); 

Ci sono anche equivalenti nello spazio dei nomi std .

Se non riesci a compilarlo, potresti usare C compilation invece di C ++. Il seguente comando di base non produce né errori né avvisi con g ++ 6.3.1, x86_64-w64-mingw32-g ++ 6.3.0, clang-x86_64 ++ 3.8.0 e Visual C ++ 2015 Community.

 g++ -std=c++11 -Wall 

Con la divisione ordinale

Quando si dividono due numeri ordinali, dove T è breve, int, lungo o un altro ordinale, l’espressione di arrotondamento è questa.

 T roundedQuotient = (2 * integerNumerator + 1) / (2 * integerDenominator); 

Precisione

Non c’è dubbio che le imprecisioni dall’aspetto strano compaiono in operazioni in virgola mobile, ma questo è solo quando appaiono i numeri, e ha poco a che fare con l’arrotondamento.

La fonte non è solo il numero di cifre significative nella mantissa della rappresentazione IEEE di un numero in virgola mobile, ma è correlata al nostro pensiero decimale come esseri umani.

Dieci è il prodotto di cinque e due, e 5 e 2 sono relativamente primi. Pertanto gli standard IEEE in virgola mobile non possono essere rappresentati perfettamente come numeri decimali per tutte le rappresentazioni digitali binarie.

Questo non è un problema con gli algoritmi di arrotondamento. È una realtà matematica che dovrebbe essere presa in considerazione durante la selezione dei tipi e la progettazione dei calcoli, l’inserimento dei dati e la visualizzazione dei numeri. Se un’applicazione mostra le cifre che mostrano questi problemi di conversione decimale-binario, allora l’applicazione sta esprimendo visivamente l’accuratezza che non esiste nella realtà digitale e dovrebbe essere modificata.

In questi giorni non dovrebbe essere un problema usare un compilatore C ++ 11 che include una libreria matematica C99 / C ++ 11. Ma poi la domanda diventa: quale funzione di arrotondamento scegli?

C99 / C ++ 11 round() spesso non è in realtà la funzione di arrotondamento desiderata . Utilizza una modalità di arrotondamento funky che va da 0 a tie-break nei casi a metà strada ( +-xxx.5000 ). Se si desidera specificamente quella modalità di arrotondamento o si sta puntando a un’implementazione C ++ dove round() è più veloce di rint() , quindi utilizzarlo (o emulare il suo comportamento con una delle altre risposte a questa domanda che lo ha preso in considerazione valore e riprodotto attentamente quel comportamento di arrotondamento specifico).

round() l’arrotondamento è diverso dal round predefinito IEEE754 alla modalità più vicina con anche come tie-break . Più vicino, persino, evita la distorsione statistica nella magnitudine media dei numeri, ma si orienta verso numeri pari.

Esistono due funzioni di arrotondamento della libreria matematica che utilizzano la modalità di arrotondamento predefinita corrente: std::nearbyint() e std::rint() , entrambe aggiunte in C99 / C ++ 11, quindi sono disponibili in qualsiasi momento std::round() è. L’unica differenza è che nearbyint non solleva mai FE_INEXACT.

Preferisci rint() per motivi di prestazioni : gcc e clang lo si nearbyint() più facilmente, ma gcc non si nearbyint() mai nelle nearbyint() (anche con -ffast-math )


gcc / clang per x86-64 e AArch64

Ho messo alcune funzioni di test in Compiler Explorer di Matt Godbolt , dove puoi vedere l’output di source + asm (per più compilatori). Per ulteriori informazioni sulla lettura dell’output del compilatore, vedere questo Q & A , e il discorso di Matt’s CppCon2017: “Che cosa ha fatto per me il mio compilatore ultimamente? Svitare il coperchio del compilatore ” ,

Nel codice FP, di solito è una grande vittoria per le piccole funzioni incorporate. Soprattutto su non-Windows, dove la convenzione di chiamata standard non ha registri preservati dalla chiamata, quindi il compilatore non può mantenere alcun valore FP nei registri XMM attraverso una call . Quindi, anche se non si conosce realmente asm, è ancora ansible vedere facilmente se si tratta solo di una chiamata di coda alla funzione di libreria o se è in linea con una o due istruzioni matematiche. Tutto ciò che è in linea con una o due istruzioni è migliore di una chiamata di funzione (per questa particolare attività su x86 o ARM).

Su x86, tutto ciò che è in linea con roundsd può auto-vectorize con SSE4.1 roundpd (o AVX vroundpd ). (FP-> le conversioni intere sono anche disponibili in forma SIMD compressa, ad eccezione di FP-> 64 bit intero che richiede AVX512.)

  • std::nearbyint() :

    • x86 clang: inline a un singolo insn con -msse4.1 .
    • x86 gcc: in linea a un singolo insn solo con -msse4.1 -ffast-math , e solo su gcc 5.4 e precedenti . Più tardi gcc non lo ha mai messo in riga (forse non si sono resi conto che uno dei bit immediati può sopprimere l’eccezione inesatta? Questo è ciò che usa clang, ma il gcc più vecchio usa lo stesso immediato di rint quando lo fa in linea)
    • AArch64 gcc6.3: inline a un singolo insn di default.
  • std::rint :

    • x86 clang: inline a un singolo insn con -msse4.1
    • x86 gcc7: inline a un singolo insn con -msse4.1 . (Senza SSE4.1, in linea con diverse istruzioni)
    • x86 gcc6.x e precedenti: inline a un singolo insn con -ffast-math -msse4.1 .
    • AArch64 gcc: inline a un singolo insn per impostazione predefinita
  • std::round :

    • x86 clang: non in linea
    • x86 gcc: inline a più istruzioni con -ffast-math -msse4.1 , che richiede due costanti vettoriali.
    • AArch64 gcc: in linea con una singola istruzione (supporto HW per questa modalità di arrotondamento, nonché IEEE predefinito e molti altri).
  • std::floor / std::ceil / std::trunc

    • x86 clang: inline a un singolo insn con -msse4.1
    • x86 gcc7.x: in linea a un singolo insn con -msse4.1
    • x86 gcc6.x e precedenti: inline a un singolo insn con -ffast-math -msse4.1
    • AArch64 gcc: inline per impostazione predefinita su una singola istruzione

Arrotondamento a int / long / long long :

Hai due opzioni qui: usa lrint (come rint ma ritorna long o long long per llrint ), o usa una funzione di arrotondamento FP-> FP e poi converti in un intero tipo nel modo normale (con troncamento). Alcuni compilatori ottimizzano in un modo meglio dell’altro.

 long l = lrint(x); int i = (int)rint(x); 

Si noti che int i = lrint(x) converte float o double -> long primo, quindi tronca il numero intero in int . Questo fa la differenza per gli interi fuori intervallo: Comportamento indefinito in C ++, ma ben definito per le istruzioni x86 FP -> int (che il compilatore emetterà a meno che non veda l’UB in fase di compilazione mentre fa propagazione costante, allora è permesso di fare il codice che si rompe se è mai eseguito).

Su x86, una conversione di interi FP-> che supera il numero intero produce INT_MIN o LLONG_MIN (un pattern a bit di 0x8000000 o equivalente a 64 bit, con solo il bit di segno impostato). Intel chiama questo valore “integer indefinite”. (Vedere la voce di manuale cvttsd2si , l’istruzione SSE2 che converte (con troncamento) double scalare in intero con cvttsd2si , disponibile con destinazione integer a 32 o 64 bit (solo in modalità a 64 bit). C’è anche un cvtsd2si (convertire con modalità di arrotondamento corrente), che è ciò che il compilatore vorrebbe emettere, ma sfortunatamente gcc e clang non lo farebbero senza -ffast-math .

Si noti inoltre che FP per / da unsigned int / long è meno efficiente su x86 (senza AVX512). La conversione a 32 bit senza segno su una macchina a 64 bit è piuttosto economica; basta convertire a 64 bit firmati e troncati. Ma altrimenti è molto più lento.

  • x86 clang con / senza -ffast-math -msse4.1 : (int/long)rint roundsd a roundsd / cvttsd2si . (ottimizzazione persa per cvtsd2si ). lrint non è affatto in linea.

  • x86 gcc6.x e precedenti senza -ffast-math : nessuna linea in linea

  • x86 gcc7 senza -ffast-math : (int/long)rint round e converte separatamente (con 2 istruzioni totali di SSE4.1 abilitato, altrimenti con un gruppo di codice inline per roundsd senza roundsd ). lrint non è in linea.
  • x86 gcc con -ffast-math : tutti i modi in linea con cvtsd2si (ottimale) , non c’è bisogno di SSE4.1.

  • AArch64 gcc6.3 senza -ffast-math : (int/long)rint rint inline a 2 istruzioni. lrint non è in linea

  • AArch64 gcc6.3 con -ffast-math : (int/long)rint compila in una chiamata a lrint . lrint non è in linea. Questo potrebbe essere un’ottimizzazione persa a meno che le due istruzioni che otteniamo senza -ffast-math siano molto lente.

Funzione double round(double) con l’uso della funzione modf :

 double round(double x) { using namespace std; if ((numeric_limits::max() - 0.5) <= x) return numeric_limits::max(); if ((-1*std::numeric_limits::max() + 0.5) > x) return (-1*std::numeric_limits::max()); double intpart; double fractpart = modf(x, &intpart); if (fractpart >= 0.5) return (intpart + 1); else if (fractpart >= -0.5) return intpart; else return (intpart - 1); } 

Per essere compilato pulito, sono necessari “math.h” e “limiti”. La funzione funziona secondo uno schema di arrotondamento seguente:

  • il giro di 5.0 è 5.0
  • il giro di 3,8 è 4.0
  • il round di 2.3 è 2.0
  • il giro di 1,5 è 2,0
  • il giro di 0,501 è 1,0
  • il giro di 0,5 è 1,0
  • il giro di 0.499 è 0.0
  • il giro di 0.01 è 0.0
  • il giro di 0.0 è 0.0
  • round di -0.01 è -0.0
  • round di -0.499 è -0.0
  • round di -0.5 è -0.0
  • il giro di -0.501 è -1.0
  • il giro di -1.5 è -1,0
  • il giro di -2,3 è -2,0
  • il giro di -3,8 è -4,0
  • round di -5,0 è -5,0

Se devi essere in grado di compilare il codice in ambienti che supportano lo standard C ++ 11, ma devi anche essere in grado di compilare lo stesso codice in ambienti che non lo supportano, potresti usare una macro funzione per scegliere tra std :: round () e una funzione personalizzata per ogni sistema. Basta passare -DCPP11 o /DCPP11 al compilatore compatibile con C ++ 11 (o usare le sue macro di versione integrate) e creare un’intestazione come questa:

 // File: rounding.h #include  #ifdef CPP11 #define ROUND(x) std::round(x) #else /* CPP11 */ inline double myRound(double x) { return (x >= 0.0 ? std::floor(x + 0.5) : std::ceil(x - 0.5)); } #define ROUND(x) myRound(x) #endif /* CPP11 */ 

Per un breve esempio, vedi http://ideone.com/zal709 .

This approximates std::round() in environments that aren’t C++11-compliant, including preservation of the sign bit for -0.0. It may cause a slight performance hit, however, and will likely have issues with rounding certain known “problem” floating-point values such as 0.49999999999999994 or similar values.

Alternatively, if you have access to a C++11-compliant compiler, you could just grab std::round() from its header, and use it to make your own header that defines the function if it’s not already defined. Note that this may not be an optimal solution, however, especially if you need to compile for multiple platforms.

Based on Kalaxy’s response, the following is a templated solution that rounds any floating point number to the nearest integer type based on natural rounding. It also throws an error in debug mode if the value is out of range of the integer type, thereby serving roughly as a viable library function.

  // round a floating point number to the nearest integer template  int Round(Arg arg) { #ifndef NDEBUG // check that the argument can be rounded given the return type: if ( (Arg)std::numeric_limits::max() < arg + (Arg) 0.5) || (Arg)std::numeric_limits::lowest() > arg - (Arg) 0.5) ) { throw std::overflow_error("out of bounds"); } #endif return (arg > (Arg) 0.0) ? (int)(r + (Arg) 0.5) : (int)(r - (Arg) 0.5); } 

As pointed out in comments and other answers, the ISO C++ standard library did not add round() until ISO C++11, when this function was pulled in by reference to the ISO C99 standard math library.

For positive operands in [½, ub ] round(x) == floor (x + 0.5) , where ub is 2 23 for float when mapped to IEEE-754 (2008) binary32 , and 2 52 for double when it is mapped to IEEE-754 (2008) binary64 . The numbers 23 and 52 correspond to the number of stored mantissa bits in these two floating-point formats. For positive operands in [+0, ½) round(x) == 0 , and for positive operands in ( ub , +∞] round(x) == x . As the function is symmetric about the x-axis, negative arguments x can be handled according to round(-x) == -round(x) .

This leads to the compact code below. It compiles into a reasonable number of machine instructions across various platforms. I observed the most compact code on GPUs, where my_roundf() requires about a dozen instructions. Depending on processor architecture and toolchain, this floating-point based approach could be either faster or slower than the integer-based implementation from newlib referenced in a different answer .

I tested my_roundf() exhaustively against the newlib roundf() implementation using Intel compiler version 13, with both /fp:strict and /fp:fast . I also checked that the newlib version matches the roundf() in the mathimf library of the Intel compiler. Exhaustive testing is not possible for double-precision round() , however the code is structurally identical to the single-precision implementation.

 #include  #include  #include  #include  #include  float my_roundf (float x) { const float half = 0.5f; const float one = 2 * half; const float lbound = half; const float ubound = 1L << 23; float a, f, r, s, t; s = (x < 0) ? (-one) : one; a = x * s; t = (a < lbound) ? x : s; f = (a < lbound) ? 0 : floorf (a + half); r = (a > ubound) ? x : (t * f); return r; } double my_round (double x) { const double half = 0.5; const double one = 2 * half; const double lbound = half; const double ubound = 1ULL << 52; double a, f, r, s, t; s = (x < 0) ? (-one) : one; a = x * s; t = (a < lbound) ? x : s; f = (a < lbound) ? 0 : floor (a + half); r = (a > ubound) ? x : (t * f); return r; } uint32_t float_as_uint (float a) { uint32_t r; memcpy (&r, &a, sizeof(r)); return r; } float uint_as_float (uint32_t a) { float r; memcpy (&r, &a, sizeof(r)); return r; } float newlib_roundf (float x) { uint32_t w; int exponent_less_127; w = float_as_uint(x); /* Extract exponent field. */ exponent_less_127 = (int)((w & 0x7f800000) >> 23) - 127; if (exponent_less_127 < 23) { if (exponent_less_127 < 0) { /* Extract sign bit. */ w &= 0x80000000; if (exponent_less_127 == -1) { /* Result is +1.0 or -1.0. */ w |= ((uint32_t)127 << 23); } } else { uint32_t 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 so raise FE_INVALID by adding */ return x + x; } else { return x; } } x = uint_as_float (w); return x; } int main (void) { uint32_t argi, resi, refi; float arg, res, ref; argi = 0; do { arg = uint_as_float (argi); ref = newlib_roundf (arg); res = my_roundf (arg); resi = float_as_uint (res); refi = float_as_uint (ref); if (resi != refi) { // check for identical bit pattern printf ("!!!! arg=%08x res=%08x ref=%08x\n", argi, resi, refi); return EXIT_FAILURE; } argi++; } while (argi); return EXIT_SUCCESS; } 

I use the following implementation of round in asm for x86 architecture and MS VS specific C++:

 __forceinline int Round(const double v) { int r; __asm { FLD v FISTP r FWAIT }; return r; } 

UPD: to return double value

 __forceinline double dround(const double v) { double r; __asm { FLD v FRNDINT FSTP r FWAIT }; return r; } 

Produzione:

 dround(0.1): 0.000000000000000 dround(-0.1): -0.000000000000000 dround(0.9): 1.000000000000000 dround(-0.9): -1.000000000000000 dround(1.1): 1.000000000000000 dround(-1.1): -1.000000000000000 dround(0.49999999999999994): 0.000000000000000 dround(-0.49999999999999994): -0.000000000000000 dround(0.5): 0.000000000000000 dround(-0.5): -0.000000000000000 
 // Convert the float to a string // We might use stringstream, but it looks like it truncates the float to only //5 decimal points (maybe that's what you want anyway =P) float MyFloat = 5.11133333311111333; float NewConvertedFloat = 0.0; string FirstString = " "; string SecondString = " "; stringstream ss (stringstream::in | stringstream::out); ss << MyFloat; FirstString = ss.str(); // Take out how ever many decimal places you want // (this is a string it includes the point) SecondString = FirstString.substr(0,5); //whatever precision decimal place you want // Convert it back to a float stringstream(SecondString) >> NewConvertedFloat; cout << NewConvertedFloat; system("pause"); 

It might be an inefficient dirty way of conversion but heck, it works lol. And it's good, because it applies to the actual float. Not just affecting the output visually.

I did this:

 #include  using namespace std; double roundh(double number, int place){ /* place = decimal point. Putting in 0 will make it round to whole number. putting in 1 will round to the tenths digit. */ number *= 10^place; int istack = (int)floor(number); int out = number-istack; if (out < 0.5){ floor(number); number /= 10^place; return number; } if (out > 0.4) { ceil(number); number /= 10^place; return number; } }