Wann müssen arithmetische Funktionen mit beliebiger Genauigkeit in PHP verwendet werden?

8

Mein Kollege verwendet die Binärrechnerfunktionen für Bandbreitenberechnungen. so viel wie Terrabyte und mit prozentualer Aufteilung bei der Zuweisung. Seine Verwendung dieser Funktionen erscheint korrekt, um kein Byte zu verlieren. obwohl er sie jetzt für alles zu benutzen scheint.

Das Handbuch sagt nur:

Für die Mathematik mit beliebiger Genauigkeit bietet PHP den Binärrechner an, der Zahlen beliebiger Größe und Genauigkeit unterstützt, die als Zeichenfolgen dargestellt werden.

Wie viel ist eine Größe? Ist es wirklich notwendig? Wie groß ist der Standard-Float in PHP? Gibt es diesbezüglich gute Ratschläge oder Dinge, die Sie beachten sollten?

Tjorriemorrie
quelle

Antworten:

13

Die Größe von Ganzzahlen in PHP ist plattformabhängig .

Die Größe einer Ganzzahl ist plattformabhängig, obwohl ein Maximalwert von etwa zwei Milliarden der übliche Wert ist (das sind 32 Bit Vorzeichen). 64-Bit-Plattformen haben normalerweise einen Maximalwert von etwa 9E18. PHP unterstützt keine vorzeichenlosen Ganzzahlen. Die Ganzzahlgröße kann mit der Konstanten PHP_INT_SIZE und der Maximalwert mit der Konstanten PHP_INT_MAX seit PHP 4.4.0 und PHP 5.0.5 bestimmt werden.

Die Größe der Schwimmer ist auch plattformabhängig :

Die Größe eines Floats ist plattformabhängig, obwohl ein Maximum von ~ 1,8e308 mit einer Genauigkeit von ungefähr 14 Dezimalstellen ein üblicher Wert ist (das 64-Bit-IEEE-Format).

und es gibt eine große rote Warnung im Handbuch über die Präzision des Schwimmers:

Gleitkommazahlen haben eine begrenzte Genauigkeit. Obwohl dies vom System abhängt, verwendet PHP normalerweise das IEEE 754-Format mit doppelter Genauigkeit, das aufgrund von Rundungen in der Größenordnung von 1.11e-16 einen maximalen relativen Fehler ergibt. Nicht elementare arithmetische Operationen können größere Fehler ergeben, und natürlich muss die Fehlerprogression berücksichtigt werden, wenn mehrere Operationen zusammengesetzt werden.

Darüber hinaus haben rationale Zahlen, die genau als Gleitkommazahlen in Basis 10 dargestellt werden können, wie 0,1 oder 0,7, keine exakte Darstellung als Gleitkommazahlen in Basis 2, die intern verwendet wird, unabhängig von der Größe der Mantisse. Daher können sie nicht ohne einen geringen Genauigkeitsverlust in ihre internen binären Gegenstücke umgewandelt werden. Dies kann zu verwirrenden Ergebnissen führen: Beispielsweise gibt Etage ((0,1 + 0,7) * 10) normalerweise 7 anstelle der erwarteten 8 zurück, da die interne Darstellung etwa 7,999999999999991111 beträgt.

Die BC Math-Erweiterung umgeht die Abhängigkeiten, sodass Sie eine große Ganzzahl explizit als Zeichenfolge angeben und die PHP-Interpretation von Ganzzahlliteralen vermeiden können. Die GMP-Funktionen sind ebenfalls gute Alternativen und funktionieren auf ähnliche Weise. Wir können davon ausgehen, dass any sizesich dies auf die maximale Größe von Zeichenfolgen bezieht, die nur durch den verfügbaren Speicher begrenzt ist :

Es ist kein Problem, wenn eine Zeichenfolge sehr groß wird. PHP setzt der Größe eines Strings keine Grenzen. Die einzige Grenze ist der verfügbare Speicher des Computers, auf dem PHP ausgeführt wird.

Ob es sinnvoll ist oder nicht, kann nur von Fall zu Fall entschieden werden. Ich habe noch nie tatsächliche Leistungsprobleme mit den Funktionen der Erweiterung bemerkt, aber mit Sicherheit sind sie nicht so schnell wie native Alternativen.


Ist es wirklich notwendig?

Es ist nur notwendig, wenn es ist, aber das ist nicht immer offensichtlich. Sie können offensichtlichen Missbrauch leicht erkennen, aber nicht so leicht über komplexere Szenarien streiten.

Besprechen Sie mit Ihrem Kollegen, warum er sie überall verwendet . Überläufe führen zu extrem hässlichen Situationen, die ich nur schwer identifizieren und lösen kann. Wenn er BC Math missbraucht, könnte dies daran liegen, dass er einmal schrecklich feststeckte und versucht, so sicher wie möglich zu sein. Obwohl die Verwendung von BC Math von Natur aus nichts auszusetzen hat, kann die ansonsten unbedeutende Leistungsminderung in mehreren Szenarien ein ernstes Problem darstellen. Wenn Sie Leistungsprobleme feststellen, stellen Sie sicher, dass Sie Ihre Anwendung profilieren und sicherstellen, dass sie mit BC Math zusammenhängt.

Denken Sie immer daran, dass Ihre Berechnungen korrekt funktionieren sollten:

  • Auf jedem System, auf das Sie abzielen, sind einzelne Entwicklermaschinen und (natürlich) Produktionsmaschinen enthalten.
  • Unabhängig von möglichen System- / Plattform-Upgrades oder -Downgrades.

Bei der Entwicklung mehrerer Plattformen sollten Sie immer die niedrigste Grenze als harte Grenze betrachten. Wenn Sie absolut sicher sind, dass Ihre Berechnungen die Grenzwerte (einschließlich ihrer Ergebnisse) nicht überschreiten, macht die Verwendung von BC Math keinen Sinn.

Aber wenn das, was Sie beschreiben , ist , dass er am liebsten echo bcadd("1", "2");über echo 1+2;, na ja, viel Glück!


Ich fand einen äußerst interessanten und relevanten Blog-Beitrag in meiner riesigen Liste von Lesezeichen, Ganzzahlen in PHP, die mit einer Schere ausgeführt werden, und Portabilität in Perconas MySQL Performance-Blog. Es ist alt (2007), bietet aber einen guten Überblick über verschiedene Snafus mit ganzzahliger Portabilität in PHP.

Yannis
quelle
1
Beachten Sie, dass die Verwendung von Zeichenfolgen für die Arithmetik mit willkürlicher Genauigkeit in keiner Weise erforderlich ist (ich stelle mir vor, dass die interne Verarbeitung ziemlich hässlich und komplex ist). Es ist nur eine einfache Möglichkeit, Literale für sie zu erhalten.
@delnan Strings werden verwendet, um Parameter in Binärrechnerfunktionen zu übergeben, da Sie die Funktionen natürlich nicht benötigen würden, wenn Sie Ganzzahlen verwenden könnten ... Das by representing arbitrary precision numbers as stringsstammt aus dem Handbuch. Haben Sie das als Vorschlag für die internen Vorgänge gelesen? ? - dh kein englischer Muttersprachler, wie könnte ich diesen Teil verbessern?
Yannis
Ja, ich denke, es könnte so gelesen werden, dass "BC Math Strings interally verwendet" (obwohl ich zum einen ein ausreichendes Verständnis der arithmetischen Präzisionsarithmetik habe, um zu bezweifeln, dass dies tatsächlich der Fall ist), da dies fast wörtlich das ist, was Sie angeben (unter dem dritten Zitat). . Ich bin auch kein Muttersprachler, aber ich stelle mir vor, es wäre sicherer zu sagen, dass man über Strings mit BC Math interagiert .
@delnan Danke, ich verstehe was du meinst. In meinen Augen deutet die Formulierung nicht darauf hin, was intern vor sich geht, da die Verwendung der Bibliothek tatsächlich dazu dient, Ihnen zu helfen, sich nicht darum zu kümmern, was intern vor sich geht, aber ich sehe, dass dies verwirrend und möglicherweise irreführend ist.
Yannis
@delnan Die Antwort wurde aktualisiert.
Yannis
4

Gibt es diesbezüglich gute Ratschläge oder Dinge, die Sie beachten sollten?

Die Verwendung der BC Math-Funktionen in PHP hat Vor- und Nachteile.

Vorteile:

  • Sie können grundlegende Berechnungen für Zahlen mit "Zahlen beliebiger Größe und Genauigkeit" durchführen.

Nachteile:

  • Berechnung ist nicht nativ (Berechnungen auf Integer oder Float sind PHP-nativ und oft CPU-nativ)
  • Zahlen, die als Zeichenfolgen verwaltet werden sollen
  • Code ist nicht leicht zu lesen

Wir können also sehen, dass BC Math für eine bestimmte Verwendung reserviert ist und möglicherweise die Formeln und sogar die Algorithmen verschleiert und auch massive Berechnungen verlangsamt .

Es ist daher eine gute Idee, Ihre Geschäftsberechnungen zu verstehen, um herauszufinden, wann solche Funktionen wirklich benötigt werden und wo sie nutzlos sind. Daher müssen Sie sich hier auf die Codegeschwindigkeit und die Lesbarkeit des Codes konzentrieren. Dann ist es angebracht, die Codierungskonvention des Projekts für die Verwendung von BC Math zu wählen.

Dazu müssen Sie die technischen Unterschiede zwischen den nativen PHP-Berechnungen und der BC Math-Funktion verstehen. Das sind Ihre Fragen "Wie groß ist eine Größe? Wie groß ist der Standard-Float in PHP?"

Wie viel ist eine Größe?

Wir können nicht viel Dokumentation über ihn finden. Wahrscheinlich solange ein String in PHP sein kann.

Wie groß ist der Standard-Float in PHP?

"Die Größe eines Floats ist plattformabhängig, obwohl ein Maximum von ~ 1,8e308 mit einer Genauigkeit von ungefähr 14 Dezimalstellen ein üblicher Wert ist (das 64-Bit-IEEE-Format)."

Weitere Details im PHP-Handbuch .

Beachten Sie, dass PHP auch GMP- Funktionen bereitstellt , die Berechnungen für große Ganzzahlen durchführen.

Skrol29
quelle
1

Ich finde bcmath viel benutzerfreundlicher als GMP. Bisher konnte ich noch nicht einmal herausfinden, wie man mit Gleitkommaberechnungen mit GMP in PHP umgeht. Alle Gleitkomma-Inhalte scheinen in der PHP-Version weggelassen worden zu sein. Also bleibe ich (vorerst) bei bcmath.

GMP auf PHP scheint auf zahlentheoretische Berechnungen ausgerichtet zu sein und nicht auf numerische Berechnungen wie Dezimalstellen von pi (oder e) und ähnlichem.

Per Kristen Fredlund
quelle
0

"Gibt es gute Ratschläge dazu oder Dinge, die man beachten sollte?"

Es gibt keinen wirklichen Ersatz für:

  1. Kenntnis der Einschränkungen Ihrer PHP-Plattform und

  2. Verständnis der Rechenanforderungen Ihres Problems.

Darüber hinaus ist ein gewisses Verständnis der Mathematik der Berechnung immer hilfreich.

Stephen C.
quelle
0
"When must arbitrary precision arithmetic functions be used in PHP?"

Ich habe noch nie von einer Site gehört, die bcmath-Funktionen in PHP für normale Praktiken verwenden muss, und denke daran, dass die meisten der größten Sites im Internet erhebliche Mengen an PHP verwenden und über 240 Millionen der "kleineren" "Sites werden mit PHP codiert.

bcmath wird normalerweise für extreme Fälle verwendet, in denen Zahlen wahrscheinlich entweder sehr groß oder sehr klein werden, anstatt in Situationen, in denen ein 'long' anstelle eines int benötigt wird oder wenn die spezifische Größe eines int oder float ein Problem darstellt.

"How much is any size?"

bcmath ist nur durch das Gedächtnis begrenzt, und in Wahrheit ist dies keine wirkliche Einschränkung. Ein schneller Test mit bcmath zeigt, dass es Zahlen größer als 2 ^ 1000000 (das sind mehr als 301.030 Stellen, eine Million sind nur sieben Stellen) und '0,1 - 2 ^ 1000000' verarbeiten kann, was zu einem Negativ mit gleichem Anteil führt.

Was die Leistung angeht, ist bcmath schnell, kann aber viel Speicher verbrauchen. Grundsätzlich werden Zahlen genauso berechnet, wie wir (als Menschen) einen Stift im Block verwenden würden. Realistische Zahlen können in nur wenigen hundert Schritten verarbeitet werden, was in der Regel nur wenige Millisekunden dauert. Aber diese 'paar hundert' String-Kopien summieren sich im Speicher. Beachten Sie, dass die obigen Zahlen (2 ^ 1000000) unglaublich groß sind und mein ziemlich alter Laptop 2-3 Sekunden braucht, um damit fertig zu werden.

"Is it really necessary?"

Kurz gesagt, ja, aber sehr selten.

Zum Beispiel sind SHA-1-Hashes tatsächlich Zahlen, keine Zeichenfolgen. Die höchstmögliche Zahl unter Verwendung von SHA-1 ist 2 ^ 160 oder 1.461.501.637.330.902.918.203.684.832.716.283.019.015.932.542.976. Es gibt keine Möglichkeit, mit solchen Zahlen unter Verwendung nativer Datentypen zu arbeiten, und die Arbeit mit SHA-1-Hashes (als Zahlen) ist in verteilten Algorithmen ziemlich häufig.

Auch dies ist selten, aber wenn es benötigt wird, gibt es wirklich keinen Ersatz, unabhängig von Ihrem System oder dem bevorzugten Rahmen.

"Advise"

Verwenden Sie bcmath nur, wenn Sie entweder wissen, dass es das ist, was Sie brauchen, oder einfach nur gerne mit Zahlen spielen. Es wird nichts kaputt machen und sollte keine merklichen Leistungsprobleme verursachen, aber die meisten Probleme können mit den Standard-Datentypen von PHP gelöst werden.

JSON
quelle
SHA-1 arbeitet intern mit mehreren 32-Bit-Ganzzahlen. Extern arbeitet es mit Byte-Sequenzen. Es ist also näher an Saiten als an großen Zahlen. Es ist selten hilfreich, es als 160-Bit-Ganzzahl zu behandeln. (Es gibt andere Bereiche der Krypto, wie RSA, die intern große Ganzzahlen verwenden, aber Sie sollten diese nicht in einer Allzweck-Bibliothek für große Ganzzahlen implementieren, da dies Seitenkanalangriffe
auslösen wird.
Hmm, ich denke MIT hatte es falsch gemacht, als sie Chord kreierten . Ich kann die Wolke bröckeln hören, während ich tippe: P
JSON
Übrigens, Sie haben Recht, wenn es um die Interna von SHA1 geht.
JSON
Der Akkord könnte einen SHA-1-Hash als große Zahl interpretieren. Nicht weil SHA-1 mit großen ganzen Zahlen zusammenhängt, sondern weil das darauf aufbauende Protokoll dies möglicherweise als zweckmäßig erachtet. DHTs verwenden eine Abstandsmetrik zwischen Hashes. Ihre können mit großen Ganzzahlen ausgedrückt werden.
CodesInChaos
Zunächst einmal sind große ganze Zahlen ein Pseudotyp. Sie existieren nativ kein System. Sie sind intern Zeichenfolgen, obwohl bei einigen Implementierungen große Ints als tatsächliche "Zahlen" im Code ausgedrückt werden können (1234323456654322345 anstelle von "1234323456654322345" wie Java). Solche Implementierungen erzeugen immer noch Zeichenfolgen, wenn der Zahlencode kompiliert wird.
JSON