BCMATHを備えたPHPでの固定点数学、精密損失ケース
特にPHPおよびMySQLで開発する場合、固定点値を処理する場合、極端な注意が必要です。この記事では、PHP BCMATH拡張機能、MySQL固定点式処理、およびPHPからMySQLへの永続的な固定点データを使用する際に遭遇する障害と詳細について説明します。いくつかの課題にもかかわらず、固定点の値を処理し、精度の損失を回避する方法を見つけようとします。
キーポイントの概要PHPのBCMATH拡張は、任意の精密数学操作をサポートしますが、数値変数がその関数に渡されると精度の損失をもたらす可能性があります。数字を表す文字列値は、この問題を回避するために代わりに使用する必要があります。
- MySQLは固定点数値式をサポートしていますが、オペランドが指数関数的または文字列形式である場合、フローティングポイント数と見なされます。 PHP PDO拡張には、バインディングの小数パラメータータイプがないため、結果が不正確になる可能性があります。
- PHP MySQLアプリケーションで正確な数学操作を実行するには、すべての操作をPHPで処理でき、データは挿入ステートメントまたは更新ステートメントを使用してMySQLにのみ持続できます。または、SQLクエリを手動で構築して、すべてのSQL数学式が10進数で表されるようにすることができます。
- bcmathの問題
bcmathドキュメントの記述:
任意の精度数学操作の場合、PHPは、文字列として表されるあらゆるサイズと精密な数値をサポートするバイナリ計算機を提供します。
ケース1したがって、BCMATH関数パラメーターは文字列として表す必要があります。数値変数をBCMATH関数に渡すと、二重値を文字列として扱うときに発生するものと同じ精度損失が誤った結果をもたらす可能性があります。
結果は次のとおりです
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;
ケース2
<code>77621.00 77621.100 77621.0100 5001885077621.00 5001885077621.100 5001885077621.00 //此处可见精度损失</code>
結果は次のとおりです
その理由は、BCMATHがパラメーターを文字列に変換し、場合によっては数字の文字列表現に指数表現があることです。
echo bcmul('10', 0.0001, 10) . PHP_EOL; echo bcmul('10', 0.00001, 10) . PHP_EOL; echo 10*0.00001 . PHP_EOL;
ケース3
<code>0.0010 0 // 这真的很奇怪!!! 0.0001</code>
PHPは弱い型言語であり、場合によっては入力を厳密に制御しないことです。できるだけ多くのリクエストを処理することを考えてください。
たとえば、ケース2
およびecho bcmul('10', '1e-4', 10) . PHP_EOL; // 也输出 0
:
を「修正」することができます。ただし、同じ変換を適用すると、ケース1:の「正しい」動作が破壊されます。
したがって、sprintfソリューションはBCMATHで動作しません。すべてのユーザー入力が文字列であると仮定すると、すべての指数表記の数をキャプチャし、それらを正しく変換する単純な検証装置を実装できます。この手法はPHPバイナーズで実装されているため、正確性を失うことなく、1E-20や50018850776.2101などのパラメーターを安全に渡すことができます。$val = sprintf("%.10f", '1e-5'); echo bcmul('10', $val, 10) . PHP_EOL; // 给我们 0.0001000000
bcmath最終ガイドライン
BCMATH PHP拡張機能の固定点操作パラメーターとして浮動小数点数を使用しないでください。文字列のみを使用します。
BCMATH拡張操作を使用する場合、指数表記のパラメーターに注意してください。 BCMATH関数は、指数パラメーター(「1E-8」など)を正しく処理しないため、手動で変換する必要があります。 SPRINTFまたは同様の変換技術を使用しないように注意してください。これにより、精度が失われます。
PHP-Bignumbersライブラリを使用できます。これにより、入力パラメーターを指数形式で処理し、ユーザーに固定点数学操作を提供できます。ただし、そのパフォーマンスはBCMATH拡張ほど良くないため、堅牢なパッケージとパフォーマンスの間のトレードオフです。
mysqlおよび固定点数
mysqlでは、10進数列タイプを使用して固定点数が処理されます。データ型と正確な数学操作については、公式のMySQLドキュメントを読むことができます。最も興味深い部分は、mysqlが式を処理する方法です:
数値式の処理は、式に含まれる値のタイプに依存します。これはシンプルに見えますが、PHPで処理する方法を見てみましょう。近似が存在する場合、式は近似であり、浮動小数点操作を使用して計算されます。
近似が存在しない場合、式には正確な値のみが含まれます。正確な値に分数部分(小数点後の値)が含まれている場合、式は65桁の精度で小数の正確算術を使用して計算されます。 「精度」という言葉は、バイナリで表現できるものによって制限されます。たとえば、1.0/3.0は、10進表記を使用して.333に近似できますが、正確な数値として記述することはできないため、(1.0/3.0)*3.0は1.0として不正確に計算されます。
それ以外の場合、式には整数値のみが含まれます。式は正確であり、bigint(64ビット)と同じ精度で整数算術を使用して計算されます。数値式に任意の文字列が含まれている場合、二重精度の浮動小数点値に変換され、式はおおよその値です。
これは、小数部の場合を示す短い例です。
PHPおよびMySQL
での正確な数学操作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;
値をステートメントプレースホルダーにバインドすると、BindValueの3番目のパラメーターを使用してそのタイプを指定できます。可能なタイプは、定数PDO :: PARAM_BOOL、PDO :: PARAM_NULL、PDO :: PARAM_INT、PDO :: PARAM_STR、PDO :: PARAM_LOB、およびPDO :: PARAM_STMTで表されます。したがって、問題は、PHP PDO拡張にバインディング用の小数パラメータータイプがないことです。その結果、クエリ内のすべての数学的式は、固定点式ではなく、浮動小数点式として扱われます。
前処理ステートメントを利用して固定点番号を使用したい場合、最良の方法はPHPですべての数学を実行し、結果をMySQLに保存することです。
<code>77621.00 77621.100 77621.0100 5001885077621.00 5001885077621.100 5001885077621.00 //此处可见精度损失</code>
結論
次の結論に達しました:
- BCMATH PHP拡張機能の固定点操作パラメーターとして浮動小数点数を使用しないでください。文字列のみを使用します。
- bcmath拡張子は、指数表記の文字列番号には適用されません。
- MySQLは固定点数値式をサポートしていますが、すべてのオペランドは10進形式でなければなりません。少なくとも1つのパラメーターが指数または文字列形式である場合、それは浮動小数点数として扱われ、式は浮動小数点数として計算されます。
- PHP PDO拡張機能には小数パラメータータイプがないため、固定点オペランドを含むSQL式でプリプロセシングステートメントとバインドパラメーターを使用しても、正確な結果は得られません。
- PHP MySQLアプリケーションで正確な数学操作を実行するには、2つの方法から選択できます。最初の方法は、PHPですべての操作を処理し、挿入ステートメントまたは更新ステートメントのみを使用してMySQLにデータを持続することです。この場合、前処理されたステートメントとパラメーターバインディングを使用できます。 2番目のアプローチは、SQLクエリを手動で構築することです(前処理ステートメントを使用できますが、パラメーターを自分で逃れる必要があります)。
私の個人的なお気に入りの方法は最初です:PHPですべての数学を実行してください。 PHPとMySQLは、正確な数学操作を必要とするアプリケーションに最適な選択肢ではないかもしれませんが、この技術スタックを選択した場合、それを正しく処理する方法を知ることは良いことです。
(スペースの制限のため、FAQの部分は省略されています。必要に応じて、FAQ部品は個別に生成できます。)
以上がBCMATHを備えたPHPでの固定点数学、精密損失ケースの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック











JWTは、JSONに基づくオープン標準であり、主にアイデンティティ認証と情報交換のために、当事者間で情報を安全に送信するために使用されます。 1。JWTは、ヘッダー、ペイロード、署名の3つの部分で構成されています。 2。JWTの実用的な原則には、JWTの生成、JWTの検証、ペイロードの解析という3つのステップが含まれます。 3. PHPでの認証にJWTを使用する場合、JWTを生成および検証でき、ユーザーの役割と許可情報を高度な使用に含めることができます。 4.一般的なエラーには、署名検証障害、トークンの有効期限、およびペイロードが大きくなります。デバッグスキルには、デバッグツールの使用とロギングが含まれます。 5.パフォーマンスの最適化とベストプラクティスには、適切な署名アルゴリズムの使用、有効期間を合理的に設定することが含まれます。

セッションハイジャックは、次の手順で達成できます。1。セッションIDを取得します。2。セッションIDを使用します。3。セッションをアクティブに保ちます。 PHPでのセッションハイジャックを防ぐための方法には次のものが含まれます。1。セッション_regenerate_id()関数を使用して、セッションIDを再生します。2。データベースを介してストアセッションデータを3。

php8.1の列挙関数は、指定された定数を定義することにより、コードの明確さとタイプの安全性を高めます。 1)列挙は、整数、文字列、またはオブジェクトであり、コードの読みやすさとタイプの安全性を向上させることができます。 2)列挙はクラスに基づいており、トラバーサルや反射などのオブジェクト指向の機能をサポートします。 3)列挙を比較と割り当てに使用して、タイプの安全性を確保できます。 4)列挙は、複雑なロジックを実装するためのメソッドの追加をサポートします。 5)厳密なタイプのチェックとエラー処理は、一般的なエラーを回避できます。 6)列挙は魔法の価値を低下させ、保守性を向上させますが、パフォーマンスの最適化に注意してください。

PHP開発における固体原理の適用には、次のものが含まれます。1。単一責任原則(SRP):各クラスは1つの機能のみを担当します。 2。オープンおよびクローズ原理(OCP):変更は、変更ではなく拡張によって達成されます。 3。Lischの代替原則(LSP):サブクラスは、プログラムの精度に影響を与えることなく、基本クラスを置き換えることができます。 4。インターフェイス分離原理(ISP):依存関係や未使用の方法を避けるために、細粒インターフェイスを使用します。 5。依存関係の反転原理(DIP):高レベルのモジュールと低レベルのモジュールは抽象化に依存し、依存関係噴射を通じて実装されます。

phpstormでCLIモードをデバッグする方法は? PHPStormで開発するときは、PHPをコマンドラインインターフェイス(CLI)モードでデバッグする必要がある場合があります。

PHP開発でPHPのCurlライブラリを使用してJSONデータを送信すると、外部APIと対話する必要があることがよくあります。一般的な方法の1つは、Curlライブラリを使用して投稿を送信することです。

静的結合(静的::) PHPで後期静的結合(LSB)を実装し、クラスを定義するのではなく、静的コンテキストで呼び出しクラスを参照できるようにします。 1)解析プロセスは実行時に実行されます。2)継承関係のコールクラスを検索します。3)パフォーマンスオーバーヘッドをもたらす可能性があります。
