web-dev-qa-db-fra.com

La notation scientifique est-elle sûre pour les constantes entières en C?

Depuis un moment, je représente de grandes puissances de 10 en constantes en utilisant la notation scientifique, juste pour ne pas avoir à compter les zéros. par exemple.

#define DELAY_USEC 1e6

Un collègue a souligné que ce n'est pas sûr, car ce n'est pas un entier et il n'est pas garanti de toujours égal à 1000000 exactement. La documentation semble le confirmer, mais je me demande si c'est vraiment pratique. Existe-t-il un moyen de déclarer en toute sécurité un entier de puissance de dix à l'aide d'un raccourci? Est-il sûr de simplement le convertir en un int dans la définition?

37
David Dombrowsky

En théorie, non. Aucun des deux langages ne précise comment les valeurs à virgule flottante sont représentées, ni quelles valeurs peuvent être représentées exactement. (MISE À JOUR: apparemment, C11 recommande une représentation. C++, et les dialectes C plus anciens, ne le font pas).

En pratique, oui, pour une gamme de valeurs assez large. Toute implémentation que vous êtes susceptible de rencontrer à distance utilise une représentation IEEE 64 bits pour double. Cela peut représenter n'importe quelle valeur entière jusqu'à 253 (environ 9x1015) exactement. Il peut certainement représenter tout ce qui peut être représenté par un type entier 32 bits.

22
Mike Seymour

Vous souhaitez utiliser des littéraux définis par l'utilisateur:

constexpr long long operator "" _k(long long l) {
    return l * 1000;
}

constexpr long long operator "" _m(long long l) {
    return l * 1000 * 1000;
}

alors vous pouvez simplement faire:

long long delay = 1_m;
long long wait = 45_k;
8
Paul Evans

Vous posez des questions précises sur les pouvoirs de dix. 1e6 sera exactement un million. Vous pouvez aller jusqu'à 1e22 sans que rien ne se passe mal. Cependant, notez qu'en C++ et C, 1e6 est une constante double, plutôt qu'une constante entière.

Les pouvoirs négatifs de dix sont une autre histoire. 1e-1 est inexact, comme le sont tous les pouvoirs inférieurs.

8
tmyklebu

Il semble que gcc suppose une constante définie en utilisant la notation scientifique comme un nombre à virgule flottante à moins qu'il ne soit converti.

Un simple code C montre ceci:

#include <stdio.h>

#define DELAY_USEC_FP  1e6
#define DELAY_USEC_INT (unsigned int) 1e6

int main()
{
    printf("DELAY_USEC_FP: %f\n", DELAY_USEC_FP);
    printf("DELAY_USEC_INT: %u\n",  DELAY_USEC_INT);
    return 0;
}

Sur une machine x86-64, gcc génère ce code d'assembly ($ gcc -S define.c):

[...]
; 0x4696837146684686336 = 1e6 in double-precision FP IEEE-754 format
movabsq $4696837146684686336, %rax
[...]
call    printf
movl    $1000000, %esi
[...]
call    printf
movl    $0, %eax

Comme indiqué ici , 10e15 et 10e22 sont la puissance maximale de dix nombres qui ont une représentation exacte au format à virgule flottante simple et double précision, respectivement.

Une puissance supérieure à dix nombres ne peut pas être représentée à l'aide de types entiers 32 bits ou 64 bits.

2
chus

Vous n'aurez jamais d'erreurs d'arrondi sur quelque chose de moins que INT_MAX, car la spécification de double met de côté 52 bits à utiliser . Votre "composant fractionnaire" n'est que votre entier, et votre "exposant" sera 1, et la virgule flottante ne lutte pas avec cela.

0
Patrick Collins

Ce n'est vraiment pas sûr car le compilateur le considérera comme un nombre à virgule flottante, donc la précision est limitée à 53 bits au lieu de 64 bits d'entiers (long int) pour plus d'informations sur la présentation des nombres à virgule flottante

http://en.wikipedia.org/wiki/Floating_point

0
Chemseddine