Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

arrondi d'un double en entier (nearbyint vs round)

3 réponses
Avatar
Isidor Ducasse
Bonjour,
Excusez si le sujet a d=E9j=E0 =E9t=E9 post=E9, je ne l'ai pas trouv=E9 dan=
s les
recherches.
Excusez, l'exemple est en C++, mais je pense que vous arriverez
facilement =E0 vous y retrouvez...

Voil=E0 mon pb, je ne comprends pas nearbyint, rint, round de la lib
math
round semble convenir =E0 mon besoin, mais qu'est-ce que c'est que cet
arrondi =E0 l'entier impair le plus proche?
A quelle correspondance math=E9matique ou convention, nearbyint et rint
font-elles r=E9f=E9rence??

le code de test suivi du r=E9sultat:
<code>
#include <cstdio>
#include <cstdlib>
#include <cmath>

void testRound(double dbl)
{
double dCeil =3D ceil(dbl);
double dFloor =3D floor(dbl);
long lMano =3D (long) (dbl + 5e-1);
long lNear =3D (long) nearbyint(dbl);
long lRint =3D (long) rint(dbl);
long lRound =3D (long) round(dbl);
double diffCeil =3D dCeil-dbl;
double diffFloor =3D dbl-dFloor;
long lMano2 =3D (long)(
diffCeil =3D=3D diffFloor ? dCeil : // explicite la convention:
si xxx.5 alors on arrondi vers ceil
diffCeil > diffFloor ? dFloor : dCeil
);

printf("| %.19f | %5.0f | %5.0f | %13.0f | %13ld | %13ld | %13ld |
%13ld | %13ld |\n",
dbl, dFloor, dCeil, dbl, lMano, lNear, lRint, lRound,
lMano2);
}

int main(int argc, const char** argv)
{
double dblArray[] =3D { 5e-1, 1.+5e-1, 2.+5e-1 }; // 0.5 1.5 2.5
int sizeA =3D sizeof(dblArray) / sizeof(double);

printf("| %-21s | %-5s | %-5s | %-13s | %-13s | %-13s | %-13s |
%-13s | %-13s |\n",
"tested value", "floor", "ceil", "print(\"%.0f\")", "(int)(x
+0.5)", "nearbyint", "rint", "round", "ceil flr near");

for (int i =3D 0; i<sizeA; i++)
{
testRound( dblArray[i] );
}

return EXIT_SUCCESS;
}
</code>

<code>
| tested value | floor | ceil | print("%.0f") | (int)(x
+0.5) | nearbyint | rint | round | ceil flr near
|
| 0.5000000000000000000 | 0 | 1 | 0 |
1 | 0 | 0 | 1 | 1 |
| 1.5000000000000000000 | 1 | 2 | 2 |
2 | 2 | 2 | 2 | 2 |
| 2.5000000000000000000 | 2 | 3 | 2 |
3 | 2 | 2 | 3 | 3 |
</code>

3 réponses

Avatar
Antoine Leca
Le 20/08/2009 11:07, Isidor Ducasse écrivit :
Voilà mon pb, je ne comprends pas nearbyint, rint, round de la lib
math



Les deux premiers sont identiques en dehors du traitement des exceptions
de résultat inexact (sujet que je ne vais pas développer, si tu ne vois
pas de quoi il retourne c'est que la différence ne t'importe pas).

round() utilise un algorithme spécifique (c'est l'algorithme que l'on
nous apprend à l'école, prendre la valeur absolue la plus grande) dans
le cas des valeurs xxx.5, indépendament des spécifications de fesetround().


round semble convenir à mon besoin, mais qu'est-ce que c'est que cet
arrondi à l'entier impair le plus proche?



Il s'agit d'un autre algorithme (souvent appelé « arrondi du banquier »,
ou plus exactement son contraire), qui à ma connaissance n'est pas
_requis_ dans une implémentation de la norme C.

L'arrondi à l'entier *pair* le plus proche (« l'arrondi du banquier »
proprement dit) est requis comme méthode par défaut par la norme IEEE754
(qui est probablement la référence utilisée par ta machine).
L'intérêt de cet algorithme par rapport à celui de round() est que les
erreurs sont statistiquement mieux réparties.


A quelle correspondance mathématique ou convention, nearbyint et rint
font-elles référence?



Suivant la valeur de fegetround():
FE_DOWNWARD comme floor()
FE_TONEAREST arrondi classique au plus proche
FE_TOWARDZERO arrondi par défaut, comme trunc(),
c'est l'effet habituel de la conversion (int)X
FE_UPWARD comme ceil()

On remarquera que (à ma connaissance) l'effet de FE_TONEAREST sur les
valeurs xxx.5 n'est pas spécifié par la norme C, on peut récupérer xxx
ou (xxx+1) suivant les implémentations; une possibilité est d'avoir
l'effet de round(), une autre serait d'arrondir vers la valeur absolue
la plus petite, on peut aussi avoir un arrondi par excès ou par défaut,
un arrondi du banquier (à l'entier pair le plus proche) ou son
contraire, voire le choix au hasard entre les deux valeurs.


le code de test suivi du résultat:



... ne concerne que ta machine.


Antoine
Avatar
Isidor Ducasse
merci, c'est clair.
Avatar
Vincent Lefevre
Dans l'article <h6jhpk$fub$,
Antoine Leca écrit:

On remarquera que (à ma connaissance) l'effet de FE_TONEAREST sur les
valeurs xxx.5 n'est pas spécifié par la norme C, on peut récupérer xxx
ou (xxx+1) suivant les implémentations; une possibilité est d'avoir
l'effet de round(), une autre serait d'arrondir vers la valeur absolue
la plus petite, on peut aussi avoir un arrondi par excès ou par défaut,
un arrondi du banquier (à l'entier pair le plus proche) ou son
contraire, voire le choix au hasard entre les deux valeurs.



Cependant, si __STDC_IEC_559__ est défini, on doit avoir la règle
de l'arrondi pair, comme l'exige la norme IEC 60559 (qui reprend
l'ancienne norme IEEE 754-1985).

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / Arénaire project (LIP, ENS-Lyon)