¿Cuándo deben usarse las funciones aritméticas de precisión arbitraria en PHP?

9

Mi colega usa las funciones de calculadora binaria en los cálculos de ancho de banda; tanto como terrabytes, y con un porcentaje de división en la asignación. Su uso de estas funciones parece correcto para no perder un byte; aunque parece estar usándolos ahora para todo.

El manual solo dice:

Para las matemáticas de precisión arbitraria, PHP ofrece la calculadora binaria que admite números de cualquier tamaño y precisión, representados como cadenas.

¿Cuánto es de cualquier tamaño? ¿Es realmente necesario? ¿Qué tan grande es el flotante predeterminado en PHP? ¿Hay algún buen consejo sobre esto o cosas a tener en cuenta?

Tjorriemorrie
fuente

Respuestas:

14

El tamaño de los enteros en PHP depende de la plataforma .

El tamaño de un número entero depende de la plataforma, aunque un valor máximo de aproximadamente dos mil millones es el valor habitual (es decir, 32 bits con signo). Las plataformas de 64 bits generalmente tienen un valor máximo de aproximadamente 9E18. PHP no admite enteros sin signo. El tamaño entero se puede determinar usando la constante PHP_INT_SIZE, y el valor máximo usando la constante PHP_INT_MAX desde PHP 4.4.0 y PHP 5.0.5.

El tamaño de los flotadores también depende de la plataforma :

El tamaño de un flotante depende de la plataforma, aunque un máximo de ~ 1.8e308 con una precisión de aproximadamente 14 dígitos decimales es un valor común (el formato IEEE de 64 bits).

y hay una gran advertencia roja en el manual sobre la precisión del flotador:

Los números de coma flotante tienen una precisión limitada. Aunque depende del sistema, PHP generalmente usa el formato de precisión doble IEEE 754, que dará un error relativo máximo debido al redondeo en el orden de 1.11e-16. Las operaciones aritméticas no elementales pueden dar errores más grandes y, por supuesto, la programación de errores debe considerarse cuando se combinan varias operaciones.

Además, los números racionales que son exactamente representables como números de coma flotante en la base 10, como 0.1 o 0.7, no tienen una representación exacta como números de coma flotante en la base 2, que se usa internamente, sin importar el tamaño de la mantisa. Por lo tanto, no se pueden convertir en sus equivalentes binarios internos sin una pequeña pérdida de precisión. Esto puede conducir a resultados confusos: por ejemplo, floor ((0.1 + 0.7) * 10) generalmente devolverá 7 en lugar de los 8 esperados, ya que la representación interna será algo así como 7.9999999999999991118 ...

La extensión BC Math evita las dependencias, lo que le permite especificar explícitamente un entero grande como una cadena, y evitar la interpretación de PHP de literales enteros. Las funciones GMP también son buenas alternativas y funcionan de manera similar. Podemos suponer con seguridad que se any sizerefiere al tamaño máximo de las cadenas, que solo está limitado por la memoria disponible :

No es problema que una cadena se vuelva muy grande. PHP no impone límites en el tamaño de una cadena; El único límite es la memoria disponible de la computadora en la que se ejecuta PHP.

Si tiene sentido o no, solo puede decidirse caso por caso. Nunca he notado ningún problema de rendimiento real con las funciones de la extensión, pero ciertamente no son tan rápidos como las alternativas nativas.


¿Es realmente necesario?

Solo es necesario cuando lo es, pero eso no siempre es obvio. Puede identificar fácilmente el abuso flagrante, pero no puede discutir con tanta facilidad sobre escenarios más complejos.

Discuta con su colega y descubra por qué los usa en todas partes . Los desbordamientos conducen a situaciones extremadamente feas, que encuentro bastante difíciles de identificar y resolver. Si está abusando de BC Math, podría ser solo porque se quedó atascado horriblemente una vez y trata de jugarlo lo más seguro posible. Aunque no hay nada intrínsecamente malo con el uso de BC Math, la penalización de rendimiento de otra manera insignificante puede ser un problema grave en varios escenarios. Si observa algún problema de rendimiento, asegúrese de perfilar su aplicación y asegúrese de que esté relacionado con BC Math.

Recuerde siempre que sus cálculos deberían funcionar correctamente:

  • En cada sistema al que se dirige, se incluyen máquinas de desarrollo individuales y (por supuesto) máquinas de producción.
  • Independientemente de las posibles actualizaciones o degradaciones del sistema / plataforma.

En el desarrollo multiplataforma, siempre debe considerar el límite más bajo como un límite estricto. Si está absolutamente seguro de que sus cálculos no superarán los límites (incluidos sus resultados), entonces no tiene sentido usar BC Math.

Pero si lo que estás describiendo es que él prefiere echo bcadd("1", "2");más echo 1+2;, bueno, buena suerte!


Encontré una publicación de blog extremadamente interesante y relevante en mi enorme lista de marcadores, Integers in PHP, corriendo con tijeras y portabilidad , en el blog MySQL Performance de Percona. Es antiguo (2007) pero ofrece una buena visión general de varios problemas con portabilidad de enteros en PHP.

Yannis
fuente
1
Tenga en cuenta que el uso de cadenas no es necesario (de hecho, me imagino que es bastante feo y complejo de manejar internamente) para la aritmética de precisión arbitraria, es solo una forma fácil de obtener literales para ellos.
@delnan Las cadenas se usan para pasar parámetros en las funciones de la Calculadora binaria, ya que, obviamente, si pudieras usar números enteros, no necesitarías las funciones ... Esto by representing arbitrary precision numbers as stringsestá tomado del manual, ¿lo leíste como una sugerencia de lo que sucede internamente? ? - es decir, no soy hablante nativo de inglés, ¿cómo podría mejorar esa parte?
yannis
Sí, creo que podría leerse que "BC Math usa cadenas de manera interna" (aunque por mi parte tengo suficiente comprensión de la aritmética de precisión arbitraria para dudar de que ese sea el caso), ya que eso es casi literalmente lo que usted dice (debajo de la tercera cita) . Tampoco soy hablante nativo, pero imagino que sería más seguro decir que uno interactúa con BC Math a través de cadenas.
@delnan Gracias, entiendo lo que quieres decir. En mi opinión, la redacción no sugiere lo que sucede internamente, ya que el uso de la biblioteca es en realidad para ayudarlo a que no le importe lo que sucede internamente, pero veo que es confuso y posiblemente engañoso.
Yannis
@delnan Actualizó la respuesta.
Yannis
4

¿Hay algún buen consejo sobre esto o cosas a tener en cuenta?

Usar las funciones BC Math en PHP tiene ventajas y desventajas.

Ventajas:

  • Puede realizar cálculos básicos en números con "números de cualquier tamaño y precisión".

Desventajas

  • el cálculo no es nativo (los cálculos en Integer o Float son nativos de PHP y a menudo nativos de CPU)
  • números como para ser manejados como cadenas
  • el código no es fácil de leer

Entonces podemos ver que BC Math está reservado para un uso específico, y puede ofuscar las fórmulas e incluso los algoritmos, y también ralentizar los cálculos masivos.

Por lo tanto, es una buena idea comprender los cálculos de su negocio para determinar cuándo se necesitan realmente esas funciones y dónde son inútiles. Por lo tanto, aquí debe centrarse en la velocidad del código y la legibilidad del código. Entonces es apropiado elegir la convención de codificación del proyecto sobre el uso de BC Math.

Para hacerlo, debe comprender las diferencias técnicas entre los cálculos nativos de PHP y la función matemática BC. Esas son sus preguntas "¿Cuánto es cualquier tamaño? ¿Qué tan grande es el flotante predeterminado en PHP?"

¿Cuánto es de cualquier tamaño?

No podemos encontrar mucha documentación sobre el suyo. Probablemente mientras una cadena pueda estar en PHP.

¿Qué tan grande es el flotante predeterminado en PHP?

"El tamaño de un flotante depende de la plataforma, aunque un máximo de ~ 1.8e308 con una precisión de aproximadamente 14 dígitos decimales es un valor común (el formato IEEE de 64 bits)".

Más detalles en el manual de PHP .

Tenga en cuenta que PHP también proporciona funciones GMP que realizan cálculos en enteros grandes.

Skrol29
fuente
1

Encuentro que bcmath es mucho más fácil de usar que GMP. Hasta ahora, ni siquiera he podido averiguar cómo lidiar con los cálculos de coma flotante con GMP en PHP. Todo el material de coma flotante parece haberse omitido en la versión de PHP. Así que me quedo con bcmath (por ahora).

GMP en PHP parece estar orientado a cálculos de teoría de números y no a cálculos numéricos como decimales de pi (oe) y similares.

Por Kristen Fredlund
fuente
0

"¿Hay algún buen consejo sobre esto o cosas a tener en cuenta?"

No hay sustituto real para:

  1. Conocer las limitaciones de su plataforma PHP, y

  2. entender los requisitos computacionales de su problema.

Además, alguna comprensión de las matemáticas de la computación siempre es útil.

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

Nunca he oído hablar de un sitio que tenga que usar funciones bcmath en PHP para lo que podría considerarse prácticas normales, y tenga en cuenta que la mayoría de los sitios más grandes en Internet usan cantidades sustanciales de PHP, y más de 240 millones de los "más pequeños "los sitios están codificados con PHP.

bcmath se usa típicamente para casos extremos donde es probable que los números se vuelvan muy grandes o muy pequeños, en lugar de situaciones en las que se necesita un 'largo' en lugar de un int, o cuando el tamaño específico de un int o flotante es una preocupación.

"How much is any size?"

bcmath solo está limitado por la memoria, y en verdad esto no es una limitación real. Una prueba rápida con bcmath muestra que puede manejar números mayores que 2 ^ 1000000 (que son 301,030+ dígitos, un millón son solo siete dígitos) y '0.1 - 2 ^ 1000000' que resulta en un negativo de igual proporción.

En cuanto al rendimiento, bcmath es rápido pero puede consumir mucha memoria. Básicamente, calcula los números de la misma manera que lo haríamos (como humanos) con un bolígrafo en la almohadilla. Los números realistas se pueden procesar en unos pocos cientos de pasos, lo que generalmente resulta en unos pocos milisegundos de tiempo. Pero estos 'pocos cientos' de copias de cadena se sumarán en la memoria. Tenga en cuenta que los números anteriores (2 ^ 1000000) son insondables y que mi portátil bastante viejo tarda 2-3 segundos en ocuparse.

"Is it really necessary?"

En resumen, sí, pero muy raramente.

Por ejemplo, los hash SHA-1 son en realidad números, no cadenas. El número más alto posible con SHA-1 es 2 ^ 160, o 1,461,501,637,330,902,918,203,684,832,716,283,019,655,932,542,976. No hay forma de trabajar con tales números usando tipos de datos nativos, y trabajar con hash SHA-1 (como números) es bastante común en algoritmos distribuidos.

De nuevo, esto es raro, pero cuando se necesita realmente no hay un sustituto, independientemente de su sistema o marco de preferencia.

"Advise"

No use bcmath a menos que sepa que es lo que necesita o simplemente disfrute jugando con números. No romperá nada y no debería causar problemas de rendimiento notables, pero la mayoría de los problemas se pueden resolver utilizando los tipos de datos estándar de PHP.

JSON
fuente
SHA-1 opera en varios enteros de 32 bits internamente. Externamente opera en secuencias de bytes. Por lo tanto, está más cerca de las cuerdas que de los grandes números. Raramente es útil tratarlo como un entero de 160 bits. (Hay otras áreas de criptografía, como RSA, que usan números enteros grandes internamente, pero no debe implementarlos en una biblioteca de números enteros de propósito general, ya que eso abrirá los ataques de canal lateral)
CodesInChaos
Hmm, supongo que MIT se equivocó cuando crearon Chord . Puedo escuchar la nube desmoronarse mientras escribo: P
JSON
Por cierto, tienes razón cuando se trata de las partes internas de SHA1.
JSON
Chord podría interpretar un hash SHA-1 como un gran número. No porque SHA-1 esté relacionado con enteros grandes, sino porque el protocolo construido encima podría resultarle conveniente hacerlo. Los DHT usan una métrica de distancia entre hashes, los suyos pueden expresarse usando enteros grandes.
CodesInChaos
En primer lugar, los enteros grandes son un pseudo tipo. No existen de forma nativa ningún sistema. Son cadenas de caracteres internamente, aunque algunas implementaciones permiten que las entradas grandes se expresen como "números" reales en el código (1234323456654322345 en lugar de "1234323456654322345", como Java). Dichas implementaciones aún crean cadenas de caracteres cuando se compila el código numérico.
JSON