Pourquoi écrire 1,000,000,000 comme 1000 * 1000 * 1000 en C?

142

Dans le code créé par Apple, il y a cette ligne:

CMTimeMakeWithSeconds( newDurationSeconds, 1000*1000*1000 )

Y a-t-il une raison d'exprimer 1,000,000,000comme 1000*1000*1000?

Pourquoi pas 1000^3d'ailleurs?

canard
la source
45
Clarté et lisibilité du code. Vous ne pouvez pas mettre, ou 'comme séparateurs dans C, donc la meilleure chose à faire est de calculer la valeur à partir d'une multiplication. ^ est un opérateur indépendant en C - OU exclusif.
Je n'existerai pas Idonotexist
54
il est surtout utilisé pour des durées comme: 2 * 60 * 60 .. c'est facile à remarquer que c'est pour 2 heures ..
Idali
53
Pour un je soupçonne que 1000000000 n'est pas une syntaxe valide
paparazzo
15
À propos, les langages de programmation modernes ont une manière alternative d'écrire la même chose, par exemple en Swift 1_000_000_000. Cependant, avec les constantes de temps, c'est plus difficile. Il est plus lisible à écrire 30 * 60(30 minutes en secondes) qu'à écrire 1800. Il existe en fait des langages qui vous permettront d'écrire des unités, par exemple meters, vous permettant de vous protéger contre les mauvaises affectations.
Sulthan
29
^est un XOR, pas un exposant ou un opérateur puissant.
3Dave

Réponses:

200

L'une des raisons de déclarer des constantes de manière multiplicative est d'améliorer la lisibilité, tandis que les performances d'exécution ne sont pas affectées. Aussi, pour indiquer que l'écrivain pensait de manière multiplicative au nombre.

Considère ceci:

double memoryBytes = 1024 * 1024 * 1024;

C'est clairement mieux que:

double memoryBytes = 1073741824;

car ce dernier ne regarde pas, à première vue, la troisième puissance de 1024.

Comme l'a mentionné Amin Negm-Awad, l' ^opérateur est le binaire XOR. De nombreux langages ne disposent pas de l'opérateur d'exponentiation intégré à la compilation, d'où la multiplication.

Piotr Falkowski
la source
13
Et dans les langages qui ont un opérateur d'exponentiation, ce n'est pas nécessairement «^». Dans Fortran, par exemple, c'est «**».
jamesqf
4
Vous devriez également inclure un lien pointant vers la mise en garde importante, donnée dans la réponse ci-dessous, de @chux: stackoverflow.com/a/40637622/1841533 (d'autant plus que l'OP a marqué "c", qui est très sensible à ce 'droitier l'opération latérale semble avoir tous les termes limités à un type plus petit, et par conséquent, le problème de multiplication peut déborder). securecoding.cert.org/confluence/display/c/… peut aider à éviter ceux-ci dans le cas général?
Olivier Dulac
4
Notons également que le calcul est effectué au moment de la compilation. Le standard C exige que l'implémentation soit capable de calculer des expressions constantes au moment de la compilation pour diverses fonctionnalités du langage et nous pouvons supposer en toute sécurité que c'est vrai lorsqu'une expression constante est utilisée comme dans cet exemple.
ouah
13
Stocker la quantité de mémoire en double? Cela semble être une source potentielle d'erreur.
JAB
7
@supercat Je suis conscient de cela, mais en utilisant double, vous pourriez avoir un cas où, par exemple, vous voulez une partie de la plage de mémoire, vous divisez par xpour obtenir la taille de la sous-plage ... et soudainement vous avez une fraction byte, qui peut nécessiter une logique supplémentaire pour compenser.
JAB
73

Pourquoi pas 1000^3?

Le résultat de 1000^3est 1003. ^est l'opérateur bit-XOR.

Même s'il ne traite pas du Q lui-même, j'ajoute une précision. x^yn'évalue pas toujours x+ycomme dans l'exemple de l'interrogateur. Vous devez xor chaque bit. Dans le cas de l'exemple:

1111101000 (1000₁₀)
0000000011 (3₁₀)
1111101011 (1003₁₀)

Mais

1111101001 (1001₁₀)
0000000011 (3₁₀)
1111101010 (1002₁₀)
Amin Negm-Awad
la source
3
monsieur, je ne sais pas comment 1003 ^ 3 est 1003. Google et Mac Calculator indiquent 1000 ^ 3 = 1 000 000 000. peux-tu expliquer?
Mahesh
57
L' ^opérateur signifie XOR en C / C ++ / Objective-C etc. Dans les calculatrices, cela signifie généralement la puissance x-to-the-y.
Tamás Zahola
5
Bah, les bits de 1000 et 3 ne se chevauchent pas. Cela semble tellement faux.
Yakk - Adam Nevraumont
19
Les bits se chevauchent. Mais pas les 1. : -]
Amin Negm-Awad
6
@Yakk: en effet, ça a l'air si mal! ... J'espère que beaucoup de gens ne penseront pas que "A ^ B" donne toujours A + B (mais je crains que certains pourraient le faire ...)
Olivier Dulac
71

Il y a des raisons de ne pas utiliser 1000 * 1000 * 1000.

Avec 16 bits int, 1000 * 1000déborde. L'utilisation 1000 * 1000 * 1000réduit donc la portabilité.

Avec 32 bits int, la première ligne de code suivante déborde.

long long Duration = 1000 * 1000 * 1000 * 1000;  // overflow
long long Duration = 1000000000000;  // no overflow, hard to read

Suggérer que la valeur du prospect correspond au type de destination pour la lisibilité, la portabilité et l' exactitude.

double Duration = 1000.0 * 1000 * 1000;
long long Duration = 1000LL * 1000 * 1000 * 1000;

Il pourrait également être simple d'utiliser la enotation pour les valeurs qui sont exactement représentables sous forme de double. Bien sûr, cela conduit à savoir si doublepeut représenter exactement la valeur du nombre entier - ce qui est préoccupant avec des valeurs supérieures à 1e9. (Voir DBL_EPSILONet DBL_DIG).

long Duration = 1000000000;
// vs.
long Duration = 1e9;
chux - Réintégrer Monica
la source
5
Remarque très importante! securecoding.cert.org/confluence/display/c/ ... peut aider dans de nombreux cas?
Olivier Dulac
2
A doublepeut représenter exactement tous les nombres entiers jusqu'à 2 ^ 53 ≈ 9e15.
Edgar Bonet
3
@EdgarBonet Il est vrai que binary64 peut représenter un nombre entier jusqu'à environ 9e15. Mais C ne spécifie pas l' doubleutilisation de binary64, même s'il est très couramment utilisé. Selon la spécification C, les valeurs jusqu'à 1e9 environ sont exactement représentables. Cela dépend si vous souhaitez coder selon les spécifications ou vous fier aux pratiques courantes.
chux
4
@Patrick Les deux 1000et 1000000000000sont des constantes entières . Chacun indépendamment avec le type sélectionné parmi int, longou long long. Le compilateur utilise le premier type de ces 3 dans lequel s'inscrit la constante entière . 1000 * 1000 * 1000 * 1000se fait avec les intmathématiques comme chacun 1000dans un int. Le produit déborde de 32 bits int. 1000000000000 est certainement représentable comme un long long(ou peut-être plus étroit) - pas de débordement. Le type de cible long long Durationn'affecte pas ce "côté droit de la destruction =".
chux
2
Il est important de placer le type le plus large en premier dans la multiplication. Avec 16 bits int, long x = 1000 * 1000 * 1000L;déborderait, alors long x = 1000L * 1000 * 1000;que non.
ex nihilo le
51

Pour plus de lisibilité.

Placer des virgules et des espaces entre les zéros ( 1 000 000 000ou 1,000,000,000) produirait une erreur de syntaxe, et avoir 1000000000dans le code rend difficile de voir exactement combien de zéros il y a.

1000*1000*1000montre que c'est 10 ^ 9, car nos yeux peuvent traiter les morceaux plus facilement. De plus, il n'y a pas de coût d'exécution, car le compilateur le remplacera par la constante 1000000000.

Tamás Zahola
la source
5
Pour info, il existe un concept de séparateurs de chiffres que j'ai appris récemment. Java l'a depuis un certain temps maintenant, et C # 7.0 peut l'obtenir. Je souhaite que toutes les langues aient cette fonction de plaisir pour les yeux. :)
iheartcsharp
1
Selon le contexte, l'utilisation 1,000,000,000ne produirait pas d'erreur de syntaxe, cela signifierait simplement autre chose. Par exempleCMTimeMakeWithSeconds( newDurationSeconds, 1,000,000,000 )
Ross Ridge
2
@ JMS10 C # l'a déjà si vous installez la version préliminaire de VS15, peut être écrit sous la forme1_000_000_000
user1306322
2
Python devient _aussi le séparateur :)
Wayne Werner
2
Et C ++ a récemment obtenu le 'séparateur, en C ++ 14, donc vous pouvez l'utiliser 1'000'000'000. (Il a été choisi parce qu'il 1,000,000,000pourrait être mal interprété comme l'opérateur virgule ou 4 paramètres distincts, et _1_000_000_000c'est un nom de variable valide (mais probablement mauvais).)
Justin Time - Réintégrer Monica
27

Pour plus de lisibilité. À titre de comparaison, Java prend _en charge les nombres pour améliorer la lisibilité (d'abord proposé par Stephen Colebourne en réponse à la PROPOSITION de Derek Foster: Binary Literals for Project Coin / JSR 334). On écrirait 1_000_000_000ici.

Dans l'ordre chronologique, du support le plus ancien au plus récent:

C'est une fonctionnalité relativement nouvelle pour les langages de se rendre compte qu'ils devraient prendre en charge (et puis il y a Perl). Comme dans l'excellente réponse de chux @, 1000*1000...est une solution partielle mais ouvre le programmeur aux bogues de débordement de la multiplication même si le résultat final est un grand type.

Djechlin
la source
De nombreux langages de programmation modernes ont la même chose, par exemple Swift. Rien de nouveau.
Sulthan
AFAIK, cela vient de Perl. PL / M a utilisé $ dans le même but, par exemple: 0100 $ 0010B
ninjalj
1
Il est assez nouveau, cependant. La fonctionnalité Java a peut-être 5 ans. La plupart des autres langages prenant en charge cette syntaxe sont assez récents - Swift lui-même n'a que quelques années. Python ajoute la prise en charge de la version 3.6, qui n'a pas encore été publiée.
johncip
2
Ada prend en charge les soulignements dans les littéraux entiers depuis 33 ans maintenant.
Peter - Réintègre Monica
1
@djechlin: J'ai pris la liberté d'ajouter plus d'informations, à peu près dans l'ordre chronologique. Je me suis trompé auparavant, à en juger par le fil de discussion Project Coin, Stephen Colebourne a probablement pris l'idée de soulignement dans les littéraux entiers de Fandom et / ou Ruby. Ruby a probablement pris l'idée de Perl et Perl d'Ada.
ninjalj
7

Cela pourrait être plus simple à lire et à obtenir des associations avec le 1,000,000,000formulaire.

D'un point de vue technique, je suppose qu'il n'y a aucune différence entre le nombre direct ou la multiplication. Le compilateur le générera de toute façon sous la forme d'un milliard constant.

Si vous parlez d'objectif-c, 1000^3cela ne fonctionnera pas car il n'y a pas une telle syntaxe pour pow (c'est xor). Au lieu de cela, la pow()fonction peut être utilisée. Mais dans ce cas, ce ne sera pas optimal, ce sera un appel de fonction d'exécution et non une constante générée par le compilateur.

Madars Vi
la source
3

Pour illustrer les raisons, considérez le programme de test suivant:

$ cat comma-expr.c && gcc -o comma-expr comma-expr.c && ./comma-expr
#include <stdio.h>

#define BILLION1 (1,000,000,000)
#define BILLION2 (1000^3)

int main()
{
        printf("%d, %d\n", BILLION1, BILLION2);
}
0, 1003
$
Peter - Réintégrer Monica
la source
1
@pjvandehaar Je ne recommanderais pas d'apprendre une langue en lisant des articles de Wikipédia.
Peter - Réintègre Monica
0

Une autre façon d'obtenir un effet similaire en C pour les nombres décimaux est d'utiliser la notation littérale à virgule flottante - tant qu'un double peut représenter le nombre souhaité sans aucune perte de précision.

IEEE 754 64 bits double peut représenter n'importe quel entier non négatif <= 2 ^ 53 sans problème. En règle générale, un double long (80 ou 128 bits) peut aller encore plus loin que cela. Les conversions seront effectuées au moment de la compilation, il n'y a donc pas de surcharge d'exécution et vous recevrez probablement des avertissements s'il y a une perte de précision inattendue et que vous avez un bon compilateur.

long lots_of_secs = 1e9;
jschultz410
la source