လက်ရှိတည်နေရာ: ပင်မစာမျက်နှာ> နောက်ဆုံးရဆောင်းပါးများစာရင်း> PHP တွင် BCMUL ကိုအသုံးပြုသည့်အခါအဘယ်အမျိုးအစားပြောင်းလဲခြင်းထောင်ချောက်များကိုအာရုံစိုက်သင့်သနည်း။ အမှားတွေကိုဘယ်လိုရှောင်ရှားရမလဲ။

PHP တွင် BCMUL ကိုအသုံးပြုသည့်အခါအဘယ်အမျိုးအစားပြောင်းလဲခြင်းထောင်ချောက်များကိုအာရုံစိုက်သင့်သနည်း။ အမှားတွေကိုဘယ်လိုရှောင်ရှားရမလဲ။

gitbox 2025-06-11

在处理高精度数学运算时, php 内置的bcmul函数是一个非常有用的工具။ 它属于bcmul函数是一个非常有用的工具, 允许我们进行任意精度的乘法操作, 允许我们进行任意精度的乘法操作, bcmul虽然强大, 但在使用过程中也存在一些容易被忽视的类型转换陷阱, bcmul 虽然强大, 但在使用过程中也存在一些容易被忽视的类型转换陷阱, 但在使用过程中也存在一些容易被忽视的类型转换陷阱, 可能会导致逻辑错误或者输出结果异常, 并给出实用的规避方法, 并给出实用的规避方法။

一, bcmul 的基本用法

BCMUL (String $ num1, string ကို string)? iT $ Scale = Null): string ကို string
该函数将两个任意精度的数字相乘, 返回结果字符串။

 <span><span><span class="hljs-variable">$result</span></span><span> = </span><span><span class="hljs-title function_ invoke__">bcmul</span></span><span>(</span><span><span class="hljs-string">'1.23'</span></span><span>, </span><span><span class="hljs-string">'4.56'</span></span><span>, </span><span><span class="hljs-number">2</span></span><span>); </span><span><span class="hljs-comment">// &#36820;&#22238; '5.60'</span></span><span>
</span></span>

注意: 输入必须是字符串, 否则可能会触发意料之外的行为, 否则可能会触发意料之外的行为။


二, 常见的类型转换陷阱

1.隐式类型转换错误

如果不小心将整数或浮点数直接传入bcmul , php 并不会抛出错误, 而是会尝试转换成字符串, 而是会尝试转换成字符串, 这种转换是由底层的字符串转换机制完成的, 容易引入精度问题, 容易引入精度问题။

 <span><span><span class="hljs-variable">$floatA</span></span><span> = </span><span><span class="hljs-number">0.1</span></span><span>;
</span><span><span class="hljs-variable">$floatB</span></span><span> = </span><span><span class="hljs-number">0.2</span></span><span>;
</span><span><span class="hljs-variable">$result</span></span><span> = </span><span><span class="hljs-title function_ invoke__">bcmul</span></span><span>(</span><span><span class="hljs-variable">$floatA</span></span><span>, </span><span><span class="hljs-variable">$floatB</span></span><span>, </span><span><span class="hljs-number">10</span></span><span>); </span><span><span class="hljs-comment">// &#38169;&#35823;&#65306;&#28014;&#28857;&#31934;&#24230;&#25439;&#22833;</span></span><span>
</span></span>

浮点数在内存中并非精确表示, 0.1实际上是个无限接近的近似值, 参与运算前就已经不准确了။

解决方法:所有参与 bcmath 运算的参数都应当显式转换为字符串။

 <span><span><span class="hljs-variable">$result</span></span><span> = </span><span><span class="hljs-title function_ invoke__">bcmul</span></span><span>(</span><span><span class="hljs-string">'0.1'</span></span><span>, </span><span><span class="hljs-string">'0.2'</span></span><span>, </span><span><span class="hljs-number">10</span></span><span>); </span><span><span class="hljs-comment">// &#27491;&#30830;&#65306;'0.0200000000'</span></span><span>
</span></span>

2

如果你从数据库, api 或用户输入中获得的数据采用科学计数法, 直接传入bcmul也会出问题။

 <span><span><span class="hljs-variable">$num</span></span><span> = </span><span><span class="hljs-string">'1.2E3'</span></span><span>;
</span><span><span class="hljs-variable">$result</span></span><span> = </span><span><span class="hljs-title function_ invoke__">bcmul</span></span><span>(</span><span><span class="hljs-variable">$num</span></span><span>, </span><span><span class="hljs-string">'2'</span></span><span>, </span><span><span class="hljs-number">2</span></span><span>); </span><span><span class="hljs-comment">// &#38169;&#35823;&#65306;bcmul &#26080;&#27861;&#35299;&#26512;&#31185;&#23398;&#35745;&#25968;&#27861;</span></span><span>
</span></span>

解决方法:在传递给bcmul前, 应将科学计数法转换为普通的十进制字符串။

 <span><span><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span> </span><span><span class="hljs-title">sciToDec</span></span><span>(</span><span><span class="hljs-params"><span class="hljs-variable">$sci</span></span></span><span>) {
    </span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-title function_ invoke__">stripos</span></span><span>(</span><span><span class="hljs-variable">$sci</span></span><span>, </span><span><span class="hljs-string">'e'</span></span><span>) === </span><span><span class="hljs-literal">false</span></span><span>) </span><span><span class="hljs-keyword">return</span></span><span> </span><span><span class="hljs-variable">$sci</span></span><span>;
    </span><span><span class="hljs-variable">$parts</span></span><span> = </span><span><span class="hljs-title function_ invoke__">explode</span></span><span>(</span><span><span class="hljs-string">'e'</span></span><span>, </span><span><span class="hljs-title function_ invoke__">strtolower</span></span><span>(</span><span><span class="hljs-variable">$sci</span></span><span>));
    </span><span><span class="hljs-keyword">return</span></span><span> </span><span><span class="hljs-title function_ invoke__">bcmul</span></span><span>(</span><span><span class="hljs-variable">$parts</span></span><span>[</span><span><span class="hljs-number">0</span></span><span>], </span><span><span class="hljs-title function_ invoke__">bcpow</span></span><span>(</span><span><span class="hljs-string">'10'</span></span><span>, </span><span><span class="hljs-variable">$parts</span></span><span>[</span><span><span class="hljs-number">1</span></span><span>]));
}

</span><span><span class="hljs-variable">$result</span></span><span> = </span><span><span class="hljs-title function_ invoke__">bcmul</span></span><span>(</span><span><span class="hljs-title function_ invoke__">sciToDec</span></span><span>(</span><span><span class="hljs-string">'1.2E3'</span></span><span>), </span><span><span class="hljs-string">'2'</span></span><span>, </span><span><span class="hljs-number">2</span></span><span>); </span><span><span class="hljs-comment">// &#27491;&#30830;&#65306;'2400.00'</span></span><span>
</span></span>

3.空字符串或 null 值参与运算

传入空字符串或null时, php 会将它们当作, 这可能掩盖严重的输入错误။

 <span><span><span class="hljs-variable">$result</span></span><span> = </span><span><span class="hljs-title function_ invoke__">bcmul</span></span><span>(</span><span><span class="hljs-string">''</span></span><span>, </span><span><span class="hljs-string">'10'</span></span><span>); </span><span><span class="hljs-comment">// &#36820;&#22238; '0'</span></span><span>
</span></span>

解决方法:运算前对参数做严格校验။

 <span><span><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span> </span><span><span class="hljs-title">validateBcmathInput</span></span><span>(</span><span><span class="hljs-params"><span class="hljs-variable">$value</span></span></span><span>) {
    </span><span><span class="hljs-keyword">return</span></span><span> </span><span><span class="hljs-title function_ invoke__">is_string</span></span><span>(</span><span><span class="hljs-variable">$value</span></span><span>) &amp;&amp; </span><span><span class="hljs-title function_ invoke__">is_numeric</span></span><span>(</span><span><span class="hljs-variable">$value</span></span><span>);
}
</span></span>

三, 如何系统性地避免出错

1 ။ 使用专门的封装函数进行参数转换和校验

<span><span><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span> </span><span><span class="hljs-title">safeBcmul</span></span><span>(</span><span><span class="hljs-params"><span class="hljs-variable">$a</span></span></span><span>, </span><span><span class="hljs-variable">$b</span></span><span>, </span><span><span class="hljs-variable">$scale</span></span><span> = </span><span><span class="hljs-number">2</span></span><span>) {
    </span><span><span class="hljs-keyword">if</span></span><span> (!</span><span><span class="hljs-title function_ invoke__">is_numeric</span></span><span>(</span><span><span class="hljs-variable">$a</span></span><span>) || !</span><span><span class="hljs-title function_ invoke__">is_numeric</span></span><span>(</span><span><span class="hljs-variable">$b</span></span><span>)) {
        </span><span><span class="hljs-keyword">throw</span></span><span> </span><span><span class="hljs-keyword">new</span></span><span> </span><span><span class="hljs-built_in">InvalidArgumentException</span></span><span>(</span><span><span class="hljs-string">"&#21442;&#25968;&#24517;&#39035;&#26159;&#25968;&#20540;&#25110;&#25968;&#23383;&#23383;&#31526;&#20018;"</span></span><span>);
    }

    </span><span><span class="hljs-variable">$a</span></span><span> = </span><span><span class="hljs-title function_ invoke__">number_format</span></span><span>((</span><span><span class="hljs-keyword">float</span></span><span>)</span><span><span class="hljs-variable">$a</span></span><span>, </span><span><span class="hljs-variable">$scale</span></span><span> + </span><span><span class="hljs-number">2</span></span><span>, </span><span><span class="hljs-string">'.'</span></span><span>, </span><span><span class="hljs-string">''</span></span><span>);
    </span><span><span class="hljs-variable">$b</span></span><span> = </span><span><span class="hljs-title function_ invoke__">number_format</span></span><span>((</span><span><span class="hljs-keyword">float</span></span><span>)</span><span><span class="hljs-variable">$b</span></span><span>, </span><span><span class="hljs-variable">$scale</span></span><span> + </span><span><span class="hljs-number">2</span></span><span>, </span><span><span class="hljs-string">'.'</span></span><span>, </span><span><span class="hljs-string">''</span></span><span>);
    </span><span><span class="hljs-keyword">return</span></span><span> </span><span><span class="hljs-title function_ invoke__">bcmul</span></span><span>(</span><span><span class="hljs-variable">$a</span></span><span>, </span><span><span class="hljs-variable">$b</span></span><span>, </span><span><span class="hljs-variable">$scale</span></span><span>);
}
</span></span>

2 ။ 避免依赖浮点数中间变量

即使是短暂赋值或中间变量, 也应避免使用 float 类型။ 例如: 例如:

 <span><span><span class="hljs-comment">// &#19981;&#25512;&#33616;</span></span><span>
</span><span><span class="hljs-variable">$a</span></span><span> = </span><span><span class="hljs-number">0.123</span></span><span>;
</span><span><span class="hljs-variable">$b</span></span><span> = </span><span><span class="hljs-string">'456'</span></span><span>;
</span><span><span class="hljs-variable">$result</span></span><span> = </span><span><span class="hljs-title function_ invoke__">bcmul</span></span><span>(</span><span><span class="hljs-variable">$a</span></span><span>, </span><span><span class="hljs-variable">$b</span></span><span>, </span><span><span class="hljs-number">4</span></span><span>); </span><span><span class="hljs-comment">// &#28508;&#22312;&#31934;&#24230;&#38382;&#39064;</span></span><span>

</span><span><span class="hljs-comment">// &#25512;&#33616;</span></span><span>
</span><span><span class="hljs-variable">$a</span></span><span> = </span><span><span class="hljs-string">'0.123'</span></span><span>;
</span><span><span class="hljs-variable">$b</span></span><span> = </span><span><span class="hljs-string">'456'</span></span><span>;
</span><span><span class="hljs-variable">$result</span></span><span> = </span><span><span class="hljs-title function_ invoke__">bcmul</span></span><span>(</span><span><span class="hljs-variable">$a</span></span><span>, </span><span><span class="hljs-variable">$b</span></span><span>, </span><span><span class="hljs-number">4</span></span><span>); </span><span><span class="hljs-comment">// &#23433;&#20840;</span></span><span>
</span></span>

3 ။ 用字符串函数处理输入数据

对于来自gitbox.net等 api 等, 常常需要做格式处理။ 避免直接将 json 解析后获得的数字用于 bcmul:

 <span><span><span class="hljs-variable">$data</span></span><span> = </span><span><span class="hljs-title function_ invoke__">json_decode</span></span><span>(</span><span><span class="hljs-title function_ invoke__">file_get_contents</span></span><span>(</span><span><span class="hljs-string">'https://gitbox.net/api/price.json'</span></span><span>), </span><span><span class="hljs-literal">true</span></span><span>);
</span><span><span class="hljs-variable">$price</span></span><span> = </span><span><span class="hljs-title function_ invoke__">strval</span></span><span>(</span><span><span class="hljs-variable">$data</span></span><span>[</span><span><span class="hljs-string">'price'</span></span><span>]);
</span><span><span class="hljs-variable">$quantity</span></span><span> = </span><span><span class="hljs-string">'3'</span></span><span>;
</span><span><span class="hljs-variable">$total</span></span><span> = </span><span><span class="hljs-title function_ invoke__">bcmul</span></span><span>(</span><span><span class="hljs-variable">$price</span></span><span>, </span><span><span class="hljs-variable">$quantity</span></span><span>, </span><span><span class="hljs-number">2</span></span><span>);
</span></span>