IEEE 754 consiglia la "metà intorno a addirittura" approccio: se la parte frazionaria di d
è 0,5 quindi arrotondato al numero intero pari più vicino. Il problema è che l'arrotondamento di una parte frazionaria di 0,5 nella stessa direzione introduce bias nei risultati; quindi, devi arrotondare lo 0,5 frazionario per metà tempo e metà del tempo, quindi il bit "arrotondato al più vicino pari", arrotondando alla cifra più vicina funzionerebbe anche come farebbe una moneta equa per determinare quale strada partire.
penso che qualcosa di più simile a questo sarebbe IEEE-corretto:
#include <math.h>
int is_even(double d) {
double int_part;
modf(d/2.0, &int_part);
return 2.0 * int_part == d;
}
double round_ieee_754(double d) {
double i = floor(d);
d -= i;
if(d < 0.5)
return i;
if(d > 0.5)
return i + 1.0;
if(is_even(i))
return i;
return i + 1.0;
}
E questo dovrebbe essere C99-ish (che sembra indicare che i numeri con parti frazionarie di 0.5 devono essere arrotondati per eccesso) :
#include <math.h>
double round_c99(double x) {
return (x >= 0.0) ? floor(x + 0.5) : ceil(x - 0.5);
}
e una versione più compatta del mio primo round_c99()
, questo gestisce attraversando il confine 56bit mantissa meglio non basandosi su x+0.5
o x-0.5
essendo cose sensibili da fare:
#include <math.h>
double round_c99(double d) {
double int_part, frac_part;
frac_part = modf(d, &int_part);
if(fabs(frac_part) < 0.5)
return int_part;
return int_part > 0.0 ? int_part + 1.0 : int_part - 1.0;
}
Ciò avrà problemi se |int_part| >> 1
ma arrotonda una doppia con un grande esponente è inutile. Sono sicuro che ci siano anche NaN in tutte e tre le cose, ma il mio masochismo ha dei limiti e la programmazione numerica non è davvero la mia cosa.
Il calcolo a virgola mobile ha un ampio margine per errori impercettibili, pertanto conciso potrebbe non essere il requisito migliore.
Una soluzione ancora migliore sarebbe quella di battere il venditore del compilatore all'incirca sul viso e sul collo finché non forniscono una libreria matematica corretta.
Si noti che 'round()' è in C99, quindi non è necessariamente in tutte le librerie C in ogni caso. – chrisaycock
Le funzioni floor o ceil sono disponibili? – Cratylus
L'arrotondamento è abbastanza inutile, solo gli umani si preoccupano di questo. Gli unici che diventano un po 'impazienti di dover leggere 7 o 15 cifre nel risultato. La macchina non si cura, non si stanca. Non è un problema, printf() giri abbastanza bene. Nel caso in cui: non implementare un programma di contabilità in C senza avere una libreria che calcola in base 10. –