Quando funções aritméticas de precisão arbitrária devem ser usadas no PHP?

9

Meu colega usa as funções da Calculadora binária nos cálculos de largura de banda; tanto quanto terrabytes e com divisão percentual na alocação. Seu uso dessas funções parece correto para não perder um byte; embora ele pareça usá-los agora para tudo.

O manual diz apenas:

Para matemática de precisão arbitrária, o PHP oferece a Calculadora Binária, que suporta números de qualquer tamanho e precisão, representados como strings.

Qual é o tamanho? Isso é realmente necessário? Qual é o tamanho do float padrão no PHP? Há algum bom conselho sobre isso ou coisas a serem lembradas?

Tjorriemorrie
fonte

Respostas:

14

O tamanho dos números inteiros no PHP depende da plataforma .

O tamanho de um número inteiro depende da plataforma, embora um valor máximo de cerca de dois bilhões seja o valor usual (com 32 bits assinados). As plataformas de 64 bits geralmente têm um valor máximo de cerca de 9E18. O PHP não suporta números inteiros não assinados. O tamanho inteiro pode ser determinado usando a constante PHP_INT_SIZE e o valor máximo usando a constante PHP_INT_MAX desde o PHP 4.4.0 e o PHP 5.0.5.

O tamanho dos carros alegóricos também depende da plataforma :

O tamanho de um flutuador depende da plataforma, embora um máximo de ~ 1.8e308 com uma precisão de aproximadamente 14 dígitos decimais seja um valor comum (o formato IEEE de 64 bits).

e há um grande aviso vermelho no manual sobre precisão de flutuação:

Os números de ponto flutuante têm precisão limitada. Embora dependa do sistema, o PHP normalmente usa o formato de precisão dupla IEEE 754, que fornecerá um erro relativo máximo devido ao arredondamento na ordem de 1.11e-16. Operações aritméticas não elementares podem gerar erros maiores e, é claro, a progragação de erros deve ser considerada quando várias operações são compostas.

Além disso, números racionais que são exatamente representáveis ​​como números de ponto flutuante na base 10, como 0,1 ou 0,7, não têm uma representação exata como números de ponto flutuante na base 2, que é usada internamente, independentemente do tamanho da mantissa. Portanto, eles não podem ser convertidos em seus equivalentes binários internos sem uma pequena perda de precisão. Isso pode levar a resultados confusos: por exemplo, floor ((0.1 + 0.7) * 10) geralmente retornará 7 em vez do esperado 8, já que a representação interna será algo como 7.9999999999999991118 ....

A extensão BC Math ignora as dependências, permitindo que você especifique explicitamente um número inteiro grande como uma string e evite a interpretação do PHP de literais inteiros. As funções GMP também são boas alternativas e funcionam de maneira semelhante. Podemos assumir com segurança que any sizese refere ao tamanho máximo de strings, limitado apenas pela memória disponível :

Não há problema em que uma cadeia se torne muito grande. O PHP não impõe limites no tamanho de uma string; o único limite é a memória disponível do computador em que o PHP está sendo executado.

Se faz sentido ou não, só pode ser decidido caso a caso. Nunca notei nenhum problema real de desempenho com as funções da extensão, mas certamente elas não são tão rápidas quanto as alternativas nativas.


Isso é realmente necessário?

Só é necessário quando é, mas nem sempre é óbvio. Você pode identificar facilmente abusos flagrantes, mas não pode argumentar com facilidade em cenários mais complexos.

Discuta com seu colega e descubra por que ele os usa em todos os lugares . Os transbordamentos levam a situações extremamente feias, que acho bastante difíceis de identificar e resolver. Se ele está abusando do BC Math, pode ser porque ele ficou terrivelmente preso uma vez e tenta jogar o mais seguro possível. Embora não exista nada de inerentemente errado no uso do BC Math, a penalidade de desempenho insignificante pode ser um problema sério em vários cenários. Se você notar algum problema de desempenho, verifique o perfil de seu aplicativo e verifique se isso está relacionado ao BC Math.

Lembre-se sempre de que seus cálculos devem funcionar corretamente:

  • Em todos os sistemas que você está alvejando, incluem máquinas de desenvolvimento individuais e (é claro) máquinas de produção.
  • Independentemente de possíveis atualizações ou downgrades do sistema / plataforma.

No desenvolvimento de várias plataformas, você deve sempre considerar o limite mais baixo como um limite rígido. Se você está absolutamente certo de que seus cálculos não ultrapassarão os limites (incluindo os resultados), não faz sentido usar o BC Math.

Mas se o que você está descrevendo é que ele prefere echo bcadd("1", "2");mais echo 1+2;, bem, boa sorte!


Encontrei um post extremamente interessante e relevante em minha enorme lista de favoritos, Inteiros em PHP, com tesoura e portabilidade , no blog MySQL Performance da Percona. É antigo (2007), mas fornece uma boa visão geral de vários snafus com portabilidade inteira em PHP.

yannis
fonte
1
Observe que o uso de strings não é necessário (na verdade, eu acho que é feio e complexo de lidar internamente) para aritmética de precisão arbitrária; é apenas uma maneira fácil de obter literais para elas.
As cordas @delnan são usadas para passar parâmetros nas funções da Calculadora Binária, pois, obviamente, se você pudesse usar números inteiros, não precisaria das funções ... O texto by representing arbitrary precision numbers as stringsé retirado do manual, você leu isso como uma sugestão do que acontece internamente ? - ou seja, não um falante nativo de inglês, como eu poderia melhorar essa parte?
yannis
Sim, acho que pode ser lido como "BC Math usa seqüências de caracteres internamente" (embora eu tenha um entendimento suficiente da aritmética da precisão arbórea para duvidar que seja esse o caso), pois é quase literalmente o que você declara (abaixo da terceira citação) . Também não sou um falante nativo, mas imagino que seria mais seguro afirmar que um interage com o BC Math por meio de strings.
@ Delnan Obrigado, entendo o que você quer dizer. Na minha opinião, o fraseado não sugere o que acontece internamente, pois o uso da biblioteca é realmente para ajudá-lo a não se importar com o que acontece internamente, mas vejo que é confuso e possivelmente enganoso.
yannis
@delnan Atualizou a resposta.
yannis
4

Há algum bom conselho sobre isso ou coisas a serem lembradas?

O uso das funções matemáticas BC no PHP tem vantagens e desvantagens.

Vantagens:

  • você pode executar cálculos básicos em números com "números de qualquer tamanho e precisão".

Desvantagens:

  • o cálculo não é nativo (os cálculos em Inteiro ou Flutuante são nativos em PHP e geralmente em CPU)
  • números a serem gerenciados como strings
  • código não é fácil de ler

Portanto, podemos ver que o BC Math é reservado para um uso específico, e pode ofuscar as fórmulas e até os algoritmos, além de retardar cálculos maciços.

Portanto, é uma boa idéia entender os cálculos de negócios para descobrir quando essas funções são realmente necessárias e onde são inúteis. Portanto, aqui você precisa se concentrar na velocidade e na legibilidade do código. Então é apropriado escolher a convenção de codificação do projeto sobre o uso do BC Math.

Para fazer isso, é necessário entender as diferenças técnicas entre os cálculos nativos do PHP e a função matemática BC. Essas são as suas perguntas "Qual é o tamanho? Qual é o tamanho do flutuador padrão no PHP?"

Qual é o tamanho?

Não conseguimos encontrar muita documentação sobre a dele. Provavelmente, desde que uma string possa estar em PHP.

Qual é o tamanho do float padrão no PHP?

"O tamanho de um flutuador depende da plataforma, embora um máximo de ~ 1.8e308 com uma precisão de aproximadamente 14 dígitos decimais seja um valor comum (o formato IEEE de 64 bits)."

Mais detalhes no manual do PHP .

Observe que o PHP também fornece funções GMP que executam cálculos em números inteiros grandes.

Skrol29
fonte
1

Acho o bcmath muito mais amigável do que o GMP. Até agora, eu nem consegui descobrir como lidar com cálculos de ponto flutuante com o GMP em PHP. Todo o material de ponto flutuante parece ter sido omitido na versão PHP. Então, eu fico com bcmath (por enquanto).

O GMP no PHP parece ser voltado para cálculos da teoria dos números e não para cálculos numéricos, como decimais de pi (ou e) e similares.

Per Kristen Fredlund
fonte
0

"Existe algum bom conselho sobre isso ou coisas a serem lembradas?"

Não há substituto real para:

  1. conhecendo as limitações da sua plataforma PHP e

  2. entender os requisitos computacionais do seu problema.

Além disso, alguma compreensão da matemática da computação é sempre útil.

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

Eu nunca ouvi falar de um site ter que usar funções bcmath no PHP para o que poderia ser considerado uma prática normal, e lembre-se de que a maioria dos sites maiores da Internet usa quantidades substanciais de PHP e mais de 240 milhões dos "menores" "sites são codificados usando PHP.

bcmath é normalmente usado para casos extremos em que os números provavelmente se tornarão muito grandes ou muito pequenos, em vez de situações em que um 'longo' é necessário em vez de um int, ou quando o tamanho específico de um int ou float é uma preocupação.

"How much is any size?"

bcmath é limitado apenas pela memória e, na verdade, essa não é uma limitação real. Um teste rápido com bcmath mostra que ele pode manipular números maiores que 2 ^ 1000000 (que são 301.030 ou mais dígitos, um milhão são apenas sete dígitos) e '0,1 - 2 ^ 1000000', o que resulta em uma proporção negativa igual.

Quanto ao desempenho, o bcmath é rápido, mas pode consumir muita memória. Basicamente, calcula os números da mesma maneira que faríamos (como seres humanos) usando uma caneta no bloco. Os números realistas podem ser processados ​​em apenas algumas centenas de etapas, geralmente resultando em apenas alguns milissegundos de tempo. Mas essas 'poucas centenas' de cópias de seqüência de caracteres serão adicionadas à memória. Observe que os números acima (2 ^ 1000000) são incomensuravelmente grandes e levam meu laptop bastante antigo de 2 a 3 segundos para lidar.

"Is it really necessary?"

Em suma, sim, mas muito raramente.

Por exemplo, os hashes SHA-1 são na verdade números, não cadeias. O número mais alto possível usando SHA-1 é 2 ^ 160, ou 1.461.501.637.330.902.918.203.684.832.716.283.019.655.932.542.976. Não há como trabalhar com esses números usando tipos de dados nativos, e trabalhar com hashes SHA-1 (como números) é bastante comum em algoritmos distribuídos.

Novamente, isso é raro, mas quando é necessário, realmente não há um substituto, independentemente do seu sistema ou estrutura de preferência.

"Advise"

Não use bcmath a menos que você saiba que é o que precisa ou apenas goste de brincar com números. Ele não quebra nada e não deve causar problemas visíveis de desempenho, mas a maioria dos problemas pode ser resolvida usando os tipos de dados padrão do PHP.

JSON
fonte
O SHA-1 opera internamente em vários números inteiros de 32 bits. Externamente, opera em seqüências de bytes. Portanto, é mais próximo de strings do que de grandes números. Raramente é útil tratá-lo como um número inteiro de 160 bits. (Há outras áreas de criptografia, como o RSA, que utilizam grandes inteiros internamente, mas você não deve implementar aqueles em uma biblioteca grande número inteiro de uso geral desde que abrirá ataques de canal lateral)
CodesInChaos
Hmm, acho que o MIT estava errado quando eles criaram o Chord . Eu posso ouvir a nuvem se desfazendo enquanto digito: P
JSON
BTW, você está certo quando se trata de componentes internos do SHA1.
JSON
O acorde pode interpretar um hash SHA-1 como um número grande. Não por causa do SHA-1 está relacionado a grandes números inteiros, mas porque o protocolo construído sobre ele pode achar conveniente fazê-lo. Os DHTs usam uma métrica de distância entre os hashes; os deles podem ser expressos usando números inteiros grandes.
CodesInChaos
Primeiro, números inteiros grandes são do tipo pseudo. Eles não existem nativamente em nenhum sistema. São strings de caracteres internamente, embora algumas implementações permitam que grandes ints sejam expressas como "números" reais no código (1234323456654322345 em vez de "1234323456654322345", como Java). Tais implementações ainda criam strings de caracteres quando o código numérico é compilado.
JSON