


Mathématiques à point fixe en PHP avec BCMATH, cas de perte de précision
Défis et conseils pour les opérations numériques à point fixe dans PHP et MySQL
Des soins extrêmes sont nécessaires lors de la gestion des valeurs de points fixes, en particulier lors du développement avec PHP et MySQL. Cet article explorera les obstacles et les détails rencontrés lors de l'utilisation d'extensions de PHP BCMATH, du traitement d'expression du point fixe MySQL et de la persistance des données de point fixe de PHP à MySQL. Malgré certains défis, nous essaierons de comprendre comment gérer les valeurs de points fixes et éviter les pertes de précision.
Résumé des points clés
- L'extension BCMATH en PHP prend en charge les opérations mathématiques de précision arbitraire, mais peut entraîner une perte de précision si des variables numériques sont transmises à ses fonctions. Les valeurs de chaîne représentant les nombres doivent être utilisées à la place pour éviter ce problème.
- MySQL prend en charge les expressions numériques à point fixe, cependant, si un opérande est au format exponentiel ou chaîne, il est considéré comme un numéro de point flottant. L'extension PHP PDO n'a pas de type de paramètre décimal pour la liaison, ce qui peut entraîner des résultats inexacts.
- Pour effectuer des opérations mathématiques précises dans une application MySQL PHP, toutes les opérations peuvent être traitées en PHP et les données ne peuvent être persistées qu'à MySQL en utilisant des instructions d'insertion ou de mise à jour. Alternativement, vous pouvez créer manuellement les requêtes SQL pour vous assurer que toutes les expressions mathématiques SQL sont représentées en nombre décimales.
Problème de Bcmath
La documentation BCMath indique:
Pour les opérations de mathématiques de précision arbitraires, PHP fournit une calculatrice binaire qui prend en charge tous les nombres de taille et de précision exprimés en chaînes.
Par conséquent, les paramètres de fonction BCMATH doivent être représentés comme des chaînes. Passer une variable numérique à la fonction BCMATH peut entraîner un résultat incorrect, la même perte de précision que celle qui se produit lors du traitement d'une double valeur comme une chaîne.
cas 1
echo bcmul(776.210000, '100', 10) . PHP_EOL; echo bcmul(776.211000, '100', 10) . PHP_EOL; echo bcmul(776.210100, '100', 10) . PHP_EOL; echo bcmul(50018850776.210000, '100', 10) . PHP_EOL; echo bcmul(50018850776.211000, '100', 10) . PHP_EOL; echo bcmul(50018850776.210100, '100', 10) . PHP_EOL;
Le résultat est:
<code>77621.00 77621.100 77621.0100 5001885077621.00 5001885077621.100 5001885077621.00 //此处可见精度损失</code>
Ne passez pas les variables numériques à la fonction BCMATH, seules les valeurs de chaîne représentant des nombres sont passées. Même si les nombres de points flottants ne sont pas traités, BCMath publiera des résultats étranges:
cas 2
echo bcmul('10', 0.0001, 10) . PHP_EOL; echo bcmul('10', 0.00001, 10) . PHP_EOL; echo 10*0.00001 . PHP_EOL;
Le résultat est:
<code>0.0010 0 // 这真的很奇怪!!! 0.0001</code>
La raison en est que BCMATH convertit ses paramètres en chaînes, et dans certains cas, la représentation de chaîne des nombres a une représentation exponentielle.
cas 3
echo bcmul('10', '1e-4', 10) . PHP_EOL; // 也输出 0
PHP est un langage de type faible qui, dans certains cas, n'a pas de contrôle strict sur l'entrée - réfléchit à la gestion du plus de demandes que possible.
Par exemple, nous pouvons "corriger" cas 2 et cas 3 :
$val = sprintf("%.10f", '1e-5'); echo bcmul('10', $val, 10) . PHP_EOL; // 给我们 0.0001000000
Cependant, l'application de la même transformation détruira le comportement "correct" de cas 1 :
$val = sprintf("%.10f", '50018850776.2100000000'); echo bcmul('10', $val, 10) . PHP_EOL; echo bcmul('10', 50018850776.2100000000, 10) . PHP_EOL; 500188507762.0999908450 // 错误 500188507762.10 // 正确
Ainsi, la solution sprintf ne fonctionne pas avec BCMATH. En supposant que toutes les entrées utilisateur sont des chaînes, nous pouvons implémenter un simple validateur qui capture les nombres de toutes les notations exponentielles et les convertit correctement. Cette technique est mise en œuvre dans des bingumbers PHP, nous pouvons donc passer en toute sécurité dans des paramètres comme 1E-20 et 50018850776.2101 sans perdre la précision.
Bcmath Final Guidelines
N'utilisez pas les nombres de points flottants comme paramètres de fonctionnement à point fixe dans les fonctions d'extension BCMath PHP. Utilisez uniquement des chaînes.
Lors de l'utilisation de l'opération d'extension BCMATH, faites attention aux paramètres de la notation exponentielle. La fonction BCMATH ne gère pas correctement les paramètres exponentiels (tels que "1E-8"), ils doivent donc être convertis manuellement. Faites attention de ne pas utiliser Sprintf ou des techniques de conversion similaires, car cela entraînera une perte de précision.
La bibliothèque PHP-Bignubers peut être utilisée, qui peut gérer les paramètres d'entrée sous forme exponentielle et fournir aux utilisateurs des opérations mathématiques à virgule fixe. Cependant, ses performances ne sont pas aussi bonnes que les extensions de BCMath, il s'agit donc d'un compromis entre des packages robustes et des performances.
MySQL et numéros de point fixe
Dans MySQL, les nombres de points fixes sont traités à l'aide du type de colonne décimale. Vous pouvez lire la documentation officielle MySQL pour les types de données et les opérations mathématiques précises.
La partie la plus intéressante est la façon dont MySQL gère les expressions:
Le traitement des expressions numériques dépend du type de valeur contenue dans l'expression:
S'il existe une approximation, l'expression est une approximation et est calculée en utilisant le fonctionnement du point flottant.
Si aucune approximation n'existe, l'expression ne contient que des valeurs exactes. Si une valeur exacte contient la partie fractionnaire (la valeur après le point décimal), l'expression est calculée en utilisant une arithmétique décimale précise avec une précision à 65 chiffres. Le mot «précision» est limité par ce qui peut être représenté en binaire. Par exemple, 1,0 / 3.0 peut être approximatif à 0,333… en utilisant une notation décimale, mais ne peut pas être écrit comme des nombres exacts, donc (1.0 / 3.0) * 3.0 est mal calculé comme 1,0.
Sinon, l'expression ne contient que des valeurs entières. L'expression est précise et est calculée en utilisant l'arithmétique entier avec la même précision que Bigint (64 bits).
Si une expression numérique contient une chaîne, elle est convertie en une valeur à virgule flottante à double précision et l'expression est une valeur approximative.
Il s'agit d'un court exemple qui démontre le cas de la partie décimale:
echo bcmul(776.210000, '100', 10) . PHP_EOL; echo bcmul(776.211000, '100', 10) . PHP_EOL; echo bcmul(776.210100, '100', 10) . PHP_EOL; echo bcmul(50018850776.210000, '100', 10) . PHP_EOL; echo bcmul(50018850776.211000, '100', 10) . PHP_EOL; echo bcmul(50018850776.210100, '100', 10) . PHP_EOL;
Cela semble simple, mais voyons comment le gérer en php.
Opérations mathématiques précises dans PHP et MySQL
Alors maintenant, nous devons persister les valeurs de points fixes de PHP à MySQL. La bonne façon est d'utiliser des déclarations de prétraitement et des espaces réservés dans la requête. Ensuite, nous faisons la liaison des paramètres, tout est sûr et fiable.
<code>77621.00 77621.100 77621.0100 5001885077621.00 5001885077621.100 5001885077621.00 //此处可见精度损失</code>
Lorsque nous lions la valeur à l'espace réservé de l'instruction, nous pouvons spécifier son type via le troisième paramètre de BindValue. Les types possibles sont représentés par les constantes PDO :: Param_bool, PDO :: Param_null, PDO :: Param_int, PDO :: Param_str, PDO :: param_lob et PDO :: Param_stmt. Le problème est donc que l'extension PHP PDO n'a pas de type de paramètre décimal pour la liaison. En conséquence, toutes les expressions mathématiques dans la requête sont traitées comme des expressions de points flottants, plutôt que des expressions de points fixes.
Si nous voulons profiter des instructions de prétraitement et utiliser des numéros de point fixe, la meilleure façon est d'effectuer tous les mathématiques en PHP et d'enregistrer le résultat sur MySQL.
echo bcmul('10', 0.0001, 10) . PHP_EOL; echo bcmul('10', 0.00001, 10) . PHP_EOL; echo 10*0.00001 . PHP_EOL;
Conclusion
Nous sommes arrivés à la conclusion suivante:
- N'utilisez pas les nombres de points flottants comme paramètres de fonctionnement à point fixe dans les fonctions d'extension BCMath PHP. Utilisez uniquement des chaînes.
- L'extension bcmath ne s'applique pas aux numéros de chaîne pour la notation exponentielle.
- MySQL prend en charge les expressions numériques à point fixe, mais tous les opérandes doivent être au format décimal. Si au moins un paramètre est au format exponentiel ou à chaîne, il est traité comme un numéro de point flottant et l'expression est calculée comme un numéro de point flottant.
- L'extension PHP PDO n'a pas de type de paramètre décimal, donc si vous utilisez une instruction de prétraitement et liez les paramètres dans une expression SQL contenant des opérandes à point fixe, vous n'obtiendrez pas de résultats exacts.
- Pour effectuer des opérations mathématiques précises dans une application PHP MySQL, vous pouvez choisir parmi deux méthodes. La première méthode consiste à traiter toutes les opérations en PHP et à utiliser uniquement des instructions d'insertion ou de mise à jour pour persister les données vers MySQL. Dans ce cas, vous pouvez utiliser des instructions prétraitées et des liaisons de paramètres. La deuxième approche consiste à construire manuellement les requêtes SQL (vous pouvez toujours utiliser des instructions de prétraitement, mais vous devez échapper aux paramètres vous-même) afin que toutes les expressions mathématiques SQL soient exprimées en chiffres décimaux.
Ma méthode préférée est la première: faites tous les mathématiques en php. Je suis d'accord que PHP et MySQL ne sont peut-être pas le meilleur choix pour les applications qui nécessitent des opérations mathématiques précises, mais si vous choisissez cette pile technologique, il est bon de savoir comment le gérer correctement.
(La pièce FAQ est omise en raison des limites de l'espace. Si nécessaire, la pièce FAQ peut être générée séparément.)
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

Video Face Swap
Échangez les visages dans n'importe quelle vidéo sans effort grâce à notre outil d'échange de visage AI entièrement gratuit !

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Sujets chauds











PHP est un langage de script largement utilisé du côté du serveur, particulièrement adapté au développement Web. 1.Php peut intégrer HTML, traiter les demandes et réponses HTTP et prend en charge une variété de bases de données. 2.PHP est utilisé pour générer du contenu Web dynamique, des données de formulaire de traitement, des bases de données d'accès, etc., avec un support communautaire solide et des ressources open source. 3. PHP est une langue interprétée, et le processus d'exécution comprend l'analyse lexicale, l'analyse grammaticale, la compilation et l'exécution. 4.PHP peut être combiné avec MySQL pour les applications avancées telles que les systèmes d'enregistrement des utilisateurs. 5. Lors du débogage de PHP, vous pouvez utiliser des fonctions telles que error_reportting () et var_dump (). 6. Optimiser le code PHP pour utiliser les mécanismes de mise en cache, optimiser les requêtes de base de données et utiliser des fonctions intégrées. 7

Dans PHP, Password_Hash et Password_verify Les fonctions doivent être utilisées pour implémenter le hachage de mot de passe sécurisé, et MD5 ou SHA1 ne doit pas être utilisé. 1) Password_hash génère un hachage contenant des valeurs de sel pour améliorer la sécurité. 2) Password_verify Vérifiez le mot de passe et assurez-vous la sécurité en comparant les valeurs de hachage. 3) MD5 et SHA1 sont vulnérables et manquent de valeurs de sel, et ne conviennent pas à la sécurité de mot de passe moderne.

PHP et Python ont chacun leurs propres avantages et choisissent en fonction des exigences du projet. 1.Php convient au développement Web, en particulier pour le développement rapide et la maintenance des sites Web. 2. Python convient à la science des données, à l'apprentissage automatique et à l'intelligence artificielle, avec syntaxe concise et adaptée aux débutants.

PHP est largement utilisé dans le commerce électronique, les systèmes de gestion de contenu et le développement d'API. 1) E-commerce: Utilisé pour la fonction de panier et le traitement des paiements. 2) Système de gestion du contenu: utilisé pour la génération de contenu dynamique et la gestion des utilisateurs. 3) Développement des API: Utilisé pour le développement de l'API RESTful et la sécurité de l'API. Grâce à l'optimisation des performances et aux meilleures pratiques, l'efficacité et la maintenabilité des applications PHP sont améliorées.

Le type PHP invite à améliorer la qualité et la lisibilité du code. 1) Conseils de type scalaire: Depuis PHP7.0, les types de données de base sont autorisés à être spécifiés dans les paramètres de fonction, tels que INT, Float, etc. 2) Invite de type de retour: Assurez la cohérence du type de valeur de retour de fonction. 3) Invite de type d'union: Depuis PHP8.0, plusieurs types peuvent être spécifiés dans les paramètres de fonction ou les valeurs de retour. 4) Invite de type nullable: permet d'inclure des valeurs nulles et de gérer les fonctions qui peuvent renvoyer les valeurs nulles.

PHP est toujours dynamique et occupe toujours une position importante dans le domaine de la programmation moderne. 1) La simplicité de PHP et le soutien communautaire puissant le rendent largement utilisé dans le développement Web; 2) sa flexibilité et sa stabilité le rendent exceptionnelle dans la gestion des formulaires Web, des opérations de base de données et du traitement de fichiers; 3) PHP évolue et optimise constamment, adapté aux débutants et aux développeurs expérimentés.

PHP convient au développement Web, en particulier dans le développement rapide et le traitement du contenu dynamique, mais n'est pas bon dans les applications de la science des données et de l'entreprise. Par rapport à Python, PHP présente plus d'avantages dans le développement Web, mais n'est pas aussi bon que Python dans le domaine de la science des données; Par rapport à Java, PHP fonctionne moins bien dans les applications au niveau de l'entreprise, mais est plus flexible dans le développement Web; Par rapport à JavaScript, PHP est plus concis dans le développement back-end, mais n'est pas aussi bon que JavaScript dans le développement frontal.

PHP est principalement la programmation procédurale, mais prend également en charge la programmation orientée objet (POO); Python prend en charge une variété de paradigmes, y compris la POO, la programmation fonctionnelle et procédurale. PHP convient au développement Web, et Python convient à une variété d'applications telles que l'analyse des données et l'apprentissage automatique.
