Warum 1.000.000.000 als 1000 * 1000 * 1000 in C schreiben?


142

In von Apple erstelltem Code gibt es folgende Zeile:

CMTimeMakeWithSeconds( newDurationSeconds, 1000*1000*1000 )

Gibt es einen Grund, sich auszudrücken 1,000,000,000als 1000*1000*1000?

Warum nicht 1000^3?


45
Klarheit und Lesbarkeit des Codes. Sie können nicht oder 'als Trennzeichen in C setzen, daher ist das nächstbeste, den Wert aus einer Multiplikation zu berechnen. ^ ist ein nicht verwandter Operator in C - exklusivem ODER.
Iwillnotexist Idonotexist

54
es wird besonders für Dauern wie: 2 * 60 * 60 verwendet. Es ist leicht zu bemerken, dass es für 2 Stunden ist.
Idali

53
Zum einen vermute ich, dass 1.000.000.000 keine gültige Syntax ist
Paparazzo

15
Moderne Programmiersprachen haben übrigens eine alternative Möglichkeit, dasselbe zu schreiben, z 1_000_000_000. B. in Swift . Mit Zeitkonstanten ist dies jedoch schwieriger. Schreiben ist besser lesbar 30 * 60(30 Minuten in Sekunden) als Schreiben 1800. Es gibt tatsächlich Sprachen, mit denen Sie Einheiten schreiben können, z. B. metersum sich vor schlechten Aufgaben zu schützen.
Sulthan

29
^ist ein XOR, kein Exponent oder Power Operator.
3Dave

Antworten:


200

Ein Grund, Konstanten multiplikativ zu deklarieren, besteht darin, die Lesbarkeit zu verbessern, während die Laufzeitleistung nicht beeinträchtigt wird. Auch um anzuzeigen, dass der Autor multiplikativ über die Zahl nachdachte.

Bedenken Sie:

double memoryBytes = 1024 * 1024 * 1024;

Es ist eindeutig besser als:

double memoryBytes = 1073741824;

da letzterer auf den ersten Blick nicht die dritte Potenz von 1024 sieht.

Wie Amin Negm-Awad erwähnte, ist der ^Operator die Binärdatei XOR. In vielen Sprachen fehlt der integrierte Exponentiationsoperator zur Kompilierungszeit, daher die Multiplikation.


13
Und in Sprachen, die einen Potenzierungsoperator haben, ist es nicht unbedingt '^'. In Fortran ist es zum Beispiel '**'.
Jamesqf

4
Sie sollten auch einen Link einfügen, der auf die wichtige Einschränkung verweist, die in der folgenden Antwort von @chux angegeben ist: stackoverflow.com/a/40637622/1841533 (insbesondere als OP-Tag "c", das für diese rechte Hand sehr anfällig ist Bei der Seitenoperation scheinen alle Begriffe auf einen kleineren Typ beschränkt zu sein, und daher kann das Problem der Multiplikation überlaufen. Securecoding.cert.org/confluence/display/c/… kann helfen, diese im allgemeinen Fall zu vermeiden?
Olivier Dulac

4
Wir sollten auch beachten, dass die Berechnung zur Kompilierungszeit erfolgt. Der C-Standard erfordert, dass die Implementierung in der Lage ist, zur Kompilierungszeit konstante Ausdrücke für verschiedene Merkmale der Sprache zu berechnen, und wir können davon ausgehen, dass dies der Fall ist, wenn ein konstanter Ausdruck wie in diesem Beispiel verwendet wird.
Ouah

13
Speicherplatz doppelt speichern? Das scheint eine potenzielle Fehlerquelle zu sein.
JAB

7
@supercat Ich bin mir dessen bewusst, aber wenn Sie double verwenden, könnten Sie einen Fall haben, in dem Sie beispielsweise einen Teil des Speicherbereichs möchten, durch den Sie dividieren x, um die Größe des Unterbereichs zu erhalten ... und plötzlich haben Sie einen Bruchteil Byte, für dessen Kompensation möglicherweise zusätzliche Logik erforderlich ist.
JAB

73

Warum nicht 1000^3?

Das Ergebnis von 1000^3ist 1003. ^ist der Bit-XOR-Operator.

Auch wenn es nicht um das Q selbst geht, füge ich eine Klarstellung hinzu. x^yist nicht bewerten immer x+ywie es funktioniert in dem Beispiel des Fragestellers . Sie müssen jedes Bit xor. Im Fall des Beispiels:

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

Aber

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

3
Sir, mir ist nicht klar, wie 1003 ^ 3 1003 ist. Google und Mac Calculator zeigen 1000 ^ 3 = 1.000.000.000. können Sie erklären?
Mahesh

57
Der ^Operator bedeutet XOR in C / C ++ / Objective-C usw. In Taschenrechnern bedeutet dies normalerweise x-zu-y-Potenz.
Tamás Zahola

5
Bah, die Bits 1000 und 3 überlappen sich nicht. Das sieht so falsch aus.
Yakk - Adam Nevraumont

19
Die Bits überlappen sich. Aber nicht die Einsen. : -]
Amin Negm-Awad

6
@ Yakk: in der Tat sieht es so falsch aus! ... Ich hoffe, viele Leute werden nicht denken, dass "A ^ B" immer A + B gibt (aber ich fürchte, einige könnten ...)
Olivier Dulac

71

Es gibt Gründe, nicht zu verwenden1000 * 1000 * 1000 .

Mit 16-Bit int, 1000 * 1000überläuft. Also mit1000 * 1000 * 1000 verringert also die Portabilität.

Bei 32-Bit läuft intdie folgende erste Codezeile über.

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

Schlagen Sie vor, dass der Lead-Wert hinsichtlich Lesbarkeit, Portabilität und Korrektheit mit dem Typ des Ziels übereinstimmt .

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

Könnte auch einfach eNotation für Werte verwenden, die genau als dargestellt werden können double. Dies führt natürlich zu der Erkenntnis, ob doubleder gesamte Zahlenwert genau dargestellt werden kann - was bei Werten größer als 1e9 von Belang ist. (Siehe DBL_EPSILONund DBL_DIG).

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

5
Sehr wichtige Bemerkung! Securecoding.cert.org/confluence/display/c/… kann in vielen Fällen hilfreich sein?
Olivier Dulac

2
A doublekann genau alle ganzen Zahlen bis zu 2 ^ 53 ≈ 9e15 darstellen.
Edgar Bonet

3
@EdgarBonet Richtig, dass binary64 eine ganze Zahl bis zu ungefähr 9e15 darstellen kann. C gibt jedoch nicht die doubleVerwendung von binary64 an, obwohl es sehr häufig verwendet wird. Gemäß der C-Spezifikation sind Werte bis etwa 1e9 genau darstellbar. Es hängt davon ab, ob Sie nach Spezifikation codieren oder sich auf gängige Praktiken verlassen möchten.
chux

4
@Patrick Beide 1000und 1000000000000sind ganzzahlige Konstanten . Jeder unabhängig mit hat den Typ ausgewählt aus int, longoder long long. Der Compiler verwendet den ersten Typ der 3, in den die Ganzzahlkonstante passt. 1000 * 1000 * 1000 * 1000wird mit intMathe wie jeder 1000in einem gemacht int. Das Produkt läuft mit 32-Bit über int. 1000000000000 ist sicherlich als long long(oder möglicherweise enger) darstellbar - kein Überlauf. Der Typ des Ziels long long Durationhat keinen Einfluss auf diese "rechte Seite der =" Detemrination.
chux

2
Es ist wichtig, den breiteren Typ bei der Multiplikation an die erste Stelle zu setzen. Mit 16-Bit int, long x = 1000 * 1000 * 1000L;würde überlaufen, während long x = 1000L * 1000 * 1000;würde nicht.
Ex Nihilo

51

Zur besseren Lesbarkeit.

Das Platzieren von Kommas und Leerzeichen zwischen den Nullen ( 1 000 000 000oder 1,000,000,000) würde einen Syntaxfehler erzeugen, und wenn 1000000000der Code vorhanden ist, ist es schwierig, genau zu erkennen, wie viele Nullen vorhanden sind.

1000*1000*1000macht deutlich, dass es 10 ^ 9 ist, weil unsere Augen die Brocken leichter verarbeiten können. Außerdem fallen keine Laufzeitkosten an, da der Compiler diese durch die Konstante ersetzt 1000000000.


5
Zu Ihrer Information, es gibt ein Konzept von Zifferntrennzeichen, das ich kürzlich kennengelernt habe. Java hat es schon eine Weile und C # 7.0 kann es bekommen. Ich wünschte, alle Sprachen hätten diese Augenweide. :)
iheartcsharp

1
Abhängig vom verwendeten Kontext 1,000,000,000würde kein Syntaxfehler auftreten, sondern nur etwas anderes. Zum BeispielCMTimeMakeWithSeconds( newDurationSeconds, 1,000,000,000 )
Ross Ridge

2
@ JMS10 C # hat es bereits, wenn Sie VS15 Vorschau-Version installieren, kann geschrieben werden als1_000_000_000
user1306322

2
Python wird auch _als Trennzeichen :)
Wayne Werner

2
Und C ++ hat kürzlich das 'Trennzeichen in C ++ 14 erhalten, damit Sie es verwenden können 1'000'000'000. (Es wurde ausgewählt, weil 1,000,000,000es als Kommaoperator oder 4 verschiedene Parameter falsch interpretiert werden kann und _1_000_000_000ein gültiger (aber wahrscheinlich schlechter) Variablenname ist.)
Justin Time - Monica

27

Zur besseren Lesbarkeit. Zum Vergleich unterstützt Java _in Zahlen, um die Lesbarkeit zu verbessern (zuerst vorgeschlagen von Stephen Colebourne als Antwort auf Derek Fosters VORSCHLAG: Binäre Literale für Project Coin / JSR 334). Man würde 1_000_000_000hier schreiben .

In ungefähr chronologischer Reihenfolge, vom ältesten bis zum neuesten Support:

Es ist eine relativ neue Funktion für Sprachen, um zu erkennen, dass sie unterstützt werden sollten (und dann gibt es Perl). Wie in der ausgezeichneten Antwort von chux @ 1000*1000...ist dies eine Teillösung, öffnet den Programmierer jedoch für Fehler, die durch Überlaufen der Multiplikation entstehen, selbst wenn das Endergebnis ein großer Typ ist.


Viele moderne Programmiersprachen haben das gleiche, zB Swift. Nichts Neues.
Sulthan

AFAIK, das kommt von Perl. PL / M verwendete $ für den gleichen Zweck, zB: 0100 $ 0010B
Ninjalj

1
Es ist jedoch ziemlich neu. Die Java-Funktion ist vielleicht 5 Jahre alt. Die meisten anderen Sprachen, die diese Syntax unterstützen, sind ziemlich neu - Swift selbst ist erst einige Jahre alt. Python fügt Unterstützung in 3.6 hinzu, die noch nicht veröffentlicht wurde.
Johncip

2
Ada unterstützt seit 33 Jahren Unterstreichungen in ganzzahligen Literalen.
Peter - Monica

1
@djechlin: Ich habe mir erlaubt, weitere Informationen hinzuzufügen, ungefähr in chronologischer Reihenfolge. Ich habe mich vorher geirrt, nach dem Thread von Project Coin zu urteilen, hat Stephen Colebourne wahrscheinlich die Idee übernommen, in ganzzahligen Literalen von Fandom und / oder Ruby zu unterstreichen. Ruby hat die Idee wahrscheinlich von Perl und Perl von Ada übernommen.
Ninjalj

7

Könnte einfacher zu lesen sein und einige Assoziationen mit dem 1,000,000,000Formular erhalten.

Aus technischer Sicht gibt es wohl keinen Unterschied zwischen der direkten Zahl oder der Multiplikation. Der Compiler generiert es sowieso als konstante Milliardenzahl.

Wenn Sie über Objective-C sprechen, 1000^3funktioniert dies nicht, da es keine solche Syntax für pow gibt (es ist xor). Stattdessen kann die pow()Funktion verwendet werden. In diesem Fall ist es jedoch nicht optimal, sondern ein Laufzeitfunktionsaufruf, keine vom Compiler generierte Konstante.


3

Betrachten Sie zur Veranschaulichung der Gründe das folgende Testprogramm:

$ 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 Ich würde nicht empfehlen, eine Sprache durch das Lesen von Wikipedia-Artikeln zu lernen.
Peter - Stellen Sie Monica

0

Eine andere Möglichkeit, einen ähnlichen Effekt in C für Dezimalzahlen zu erzielen, ist die Verwendung der wörtlichen Gleitkommanotation - solange ein Double die gewünschte Zahl ohne Genauigkeitsverlust darstellen kann.

IEEE 644 64-Bit-Double kann problemlos jede nicht negative Ganzzahl <= 2 ^ 53 darstellen. In der Regel kann Long Double (80 oder 128 Bit) sogar noch weiter gehen. Die Konvertierungen werden zur Kompilierungszeit durchgeführt, sodass kein Laufzeitaufwand entsteht und Sie wahrscheinlich Warnungen erhalten, wenn ein unerwarteter Genauigkeitsverlust auftritt und Sie einen guten Compiler haben.

long lots_of_secs = 1e9;
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.