Perché scrivere 1.000.000.000 come 1000 * 1000 * 1000 in C?


142

Nel codice creato da Apple, c'è questa riga:

CMTimeMakeWithSeconds( newDurationSeconds, 1000*1000*1000 )

C'è qualche motivo per esprimere 1,000,000,000come 1000*1000*1000?

Perché non 1000^3per quello?


45
Chiarezza e leggibilità del codice. Non puoi mettere ", come separatori in C, quindi la cosa migliore da fare è calcolare il valore da una moltiplicazione. ^ è un operatore indipendente in C - OR esclusivo.
Iwillnotexist Idonotexist,

54
è stato utilizzato in particolare per durate come: 2 * 60 * 60 .. è facile notare che è per 2 ore ..
Idali

53
Per uno, ho il sospetto che 1.000.000.000 non sia una sintassi valida
paparazzo,

15
A proposito, i moderni linguaggi di programmazione hanno un modo alternativo di scrivere lo stesso, ad esempio in Swift 1_000_000_000. Tuttavia, con le costanti di tempo questo è più difficile. È più leggibile scrivere 30 * 60(30 minuti in secondi) che scrivere 1800. In realtà ci sono lingue che ti permetteranno di scrivere unità, ad esempio meters, consentendoti di proteggerti da cattivi incarichi.
Sulthan,

29
^è un XOR, non un esponente o un operatore di potenza.
3Daveva il

Risposte:


200

Un motivo per dichiarare le costanti in modo moltiplicativo è migliorare la leggibilità, mentre le prestazioni di runtime non sono influenzate. Inoltre, per indicare che lo scrittore stava pensando in modo moltiplicativo al numero.

Considera questo:

double memoryBytes = 1024 * 1024 * 1024;

È chiaramente meglio di:

double memoryBytes = 1073741824;

poiché quest'ultimo non sembra, a prima vista, la terza potenza del 1024.

Come menzionato da Amin Negm-Awad, l' ^operatore è il binario XOR. Molte lingue mancano dell'operatore esponenziale incorporato, in fase di compilazione, da cui la moltiplicazione.


13
E nelle lingue che hanno un operatore esponenziale, non è necessariamente "^". In Fortran, ad esempio, è "**".
jamesqf,

4
Si dovrebbe anche includere un link che punta al avvertimento importante, dato in risposta qui sotto, da @chux: stackoverflow.com/a/40637622/1841533 (tanto più che il PO etichettato "c", che è molto sensibili a questa 'righ mano l'operazione laterale sembra avere tutti i termini limitati a un tipo più piccolo, e quindi la moltiplicazione potrebbe traboccare il problema). securecoding.cert.org/confluence/display/c/… può aiutare a evitare quelli nel caso generale?
Olivier Dulac,

4
Inoltre, dovremmo notare che il calcolo viene eseguito al momento della compilazione. Lo standard C richiede che l'implementazione sia in grado di calcolare espressioni costanti in fase di compilazione per varie caratteristiche del linguaggio e possiamo tranquillamente presumere che sia vero quando viene usata un'espressione costante come in questo esempio.
ouah

13
Memorizzare la quantità di memoria come doppia? Sembra una potenziale fonte di errore.
JAB

7
@supercat Ne sono consapevole, ma usando il doppio potresti avere un caso in cui, diciamo, vuoi una porzione dell'intervallo di memoria, dividi xper ottenere la dimensione del sottorange ... e improvvisamente hai un frazionario byte, che potrebbe richiedere logica aggiuntiva per compensare.
JAB

73

Perché no 1000^3?

Il risultato 1000^3è 1003. ^è l'operatore bit-XOR.

Anche se non si occupa della Q stessa, aggiungo un chiarimento. x^ynon non sempre valutata come x+ycome in l'esempio del interrogante. Devi xor ogni bit. Nel caso dell'esempio:

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

Ma

1111101001 (1001₁₀)
0000000011 (3₁₀)
1111101010 (1002₁₀)

3
signore, non sono chiaro come 1003 ^ 3 sia 1003. Google e Mac Calculator mostrano 1000 ^ 3 = 1.000.000.000. Puoi spiegare?
Mahesh,

57
L' ^operatore indica XOR in C / C ++ / Objective-C ecc. Nei calcolatori di solito significa potenza da X a Y.
Tamás Zahola,

5
Bah, i bit di 1000 e 3 non si sovrappongono. Sembra così sbagliato.
Yakk - Adam Nevraumont,

19
I bit si sovrappongono. Ma non gli 1. : -]
Amin Negm-Awad,

6
@Yakk: anzi, sembra così sbagliato! ... Spero che molte persone non pensino che "A ^ B" dia sempre A + B (ma temo che alcuni potrebbero ...)
Olivier Dulac,

71

Ci sono ragioni per non usare 1000 * 1000 * 1000.

Con 16 bit int, 1000 * 1000straripa. Quindi l'utilizzo 1000 * 1000 * 1000riduce la portabilità.

Con 32 bit int, la seguente prima riga di overflow del codice.

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

Suggerire che il valore iniziale corrisponda al tipo di destinazione per leggibilità, portabilità e correttezza.

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

Inoltre potrebbe usare la semplice enotazione per valori che sono esattamente rappresentabili come a double. Naturalmente questo porta a sapere se doublepuò rappresentare esattamente l'intero valore numerico - qualcosa di preoccupante con valori maggiori di 1e9. (Vedi DBL_EPSILONe DBL_DIG).

long Duration = 1000000000;
// vs.
long Duration = 1e9;

5
Osservazione molto importante! securecoding.cert.org/confluence/display/c/… può aiutare in molti casi?
Olivier Dulac il

2
A doublepuò rappresentare esattamente tutti i numeri interi fino a 2 ^ 53 ≈ 9e15.
Edgar Bonet,

3
@EdgarBonet Vero che binary64 può rappresentare un numero intero fino a circa 9e15. Ma C non specifica l' doubleuso di binary64, anche se è molto comunemente usato. Secondo la specifica C, i valori fino a 1e9 o giù di lì sono esattamente rappresentabili. Dipende se si desidera codificare per specificare o fare affidamento su pratiche comuni.
chux - Ripristina Monica il

4
@Patrick Entrambi 1000e 1000000000000sono costanti intere . Ciascuno indipendentemente con ha il tipo selezionato da int, longo long long. Il compilatore utilizza il primo tipo di quei 3 in cui si adatta la costante intera . 1000 * 1000 * 1000 * 1000è fatto con la intmatematica come ciascuno 1000in un int. Il prodotto trabocca con 32 bit int. 1000000000000 è certamente rappresentabile come long long(o forse più stretto) - nessun overflow. Il tipo di bersaglio long long Durationnon influenza questa "destra del deteminazione".
chux - Ripristina Monica il

2
È importante inserire prima il tipo più largo nella moltiplicazione. Con 16 bit int, long x = 1000 * 1000 * 1000L;traboccerebbe, mentre long x = 1000L * 1000 * 1000;no.
ex nihilo,

51

Per leggibilità.

Posizionare virgole e spazi tra gli zeri ( 1 000 000 000o 1,000,000,000) produrrebbe un errore di sintassi e avere 1000000000nel codice rende difficile vedere esattamente quanti zeri ci sono.

1000*1000*1000rende evidente che sono 10 ^ 9, perché i nostri occhi possono elaborare i blocchi più facilmente. Inoltre, non ci sono costi di runtime, perché il compilatore lo sostituirà con la costante 1000000000.


5
Cordiali saluti, c'è un concetto di separatori di cifre che ho imparato di recente. Java lo ha da un po 'di tempo, e C # 7.0 potrebbe averlo. Vorrei che tutte le lingue avessero questa caratteristica accattivante. :)
iheartcsharp,

1
A seconda del contesto utilizzato 1,000,000,000non produrrebbe un errore di sintassi, significherebbe solo qualcos'altro. Ad esempioCMTimeMakeWithSeconds( newDurationSeconds, 1,000,000,000 )
Ross Ridge,

2
@ JMS10 C # lo ha già se si installa la versione di anteprima VS15, può essere scritto come1_000_000_000
user1306322

2
Anche Python sta diventando _il separatore :)
Wayne Werner,

2
E C ++ ha recentemente ottenuto il 'separatore, in C ++ 14, quindi puoi usarlo 1'000'000'000. (È stato scelto perché 1,000,000,000potrebbe essere erroneamente interpretato come l'operatore virgola o 4 parametri distinti, ed _1_000_000_000è un nome di variabile valido (ma probabilmente non valido).)
Justin Time - Ripristina Monica

27

Per leggibilità. Per fare un confronto, Java supporta i _numeri per migliorare la leggibilità (proposta per la prima volta da Stephen Colebourne come risposta alla PROPOSTA di Derek Foster: Binary Literals for Project Coin / JSR 334). Si scriverebbe 1_000_000_000qui.

In ordine approssimativamente cronologico, dal supporto più vecchio al più recente:

È una funzionalità relativamente nuova per le lingue rendersi conto che dovrebbero supportare (e poi c'è Perl). Come nell'eccellente risposta di chux @, 1000*1000...è una soluzione parziale, ma apre il programmatore ai bug di overflow della moltiplicazione anche se il risultato finale è di tipo elevato.


Molti linguaggi di programmazione moderni hanno lo stesso, ad esempio Swift. Niente di nuovo.
Sulthan,

AFAIK, questo viene dal Perl. PL / M ha usato $ per lo stesso scopo, ad esempio: 0100 $ 0010B
ninjalj,

1
Si è abbastanza nuovo, però. La funzione Java ha forse 5 anni. La maggior parte delle altre lingue che supportano questa sintassi sono piuttosto nuove: Swift stesso ha solo pochi anni. Python aggiunge il supporto in 3.6, che non è stato ancora rilasciato.
johncip,

2
Ada ha supportato le sottolineature in letterali interi per 33 anni.
Peter - Ripristina Monica il

1
@djechlin: mi sono preso la libertà di aggiungere ulteriori informazioni, approssimativamente in ordine cronologico. Mi ero sbagliato prima, a giudicare dal thread di Project Coin, Stephen Colebourne probabilmente ha preso l'idea del carattere di sottolineatura in letterali interi di Fandom e / o Ruby. Ruby probabilmente prese l'idea da Perl e Perl da Ada.
ninjalj,

7

Potrebbe essere più semplice da leggere e ottenere alcune associazioni con il 1,000,000,000modulo.

Dal punto di vista tecnico immagino non ci sia differenza tra il numero diretto o la moltiplicazione. Il compilatore lo genererà comunque come numero di miliardi costanti.

Se parli di object-c, allora 1000^3non funzionerà perché non esiste una sintassi simile per pow (è xor). Invece, è pow()possibile utilizzare la funzione. Ma in tal caso, non sarà ottimale, sarà una funzione di runtime chiamata non una costante generata dal compilatore.


3

Per illustrare i motivi, prendere in considerazione il seguente programma di test:

$ 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
$

1
@pjvandehaar Non consiglierei di imparare una lingua leggendo gli articoli di Wikipedia.
Peter - Ripristina Monica il

0

Un altro modo per ottenere un effetto simile in C per i numeri decimali è utilizzare la notazione letterale in virgola mobile - purché un doppio possa rappresentare il numero desiderato senza alcuna perdita di precisione.

Il doppio IEEE 754 a 64 bit può rappresentare qualsiasi numero intero non negativo <= 2 ^ 53 senza problemi. In genere, il doppio lungo (80 o 128 bit) può andare anche oltre. Le conversioni verranno eseguite al momento della compilazione, quindi non vi è alcun sovraccarico di runtime e probabilmente si riceveranno avvisi se si verifica una perdita imprevista di precisione e si dispone di un buon compilatore.

long lots_of_secs = 1e9;
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.