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.