我试图打印大数字的乘法,它们导致浮点型科学数字。
var_dump((double)('290287121823'*'290287121823'));
我尝试使用函数number_format和preg_replace删除所有','。但是在number_format之后,结果不正确。
使用以下代码:
preg_replace("/,/", "", (number_format(('290287121823'*'290287121823'))));
收到的产出:84266613096281242861568
预期正确输出:84266613096281243382112
答案 0 :(得分:0)
大数字是按位数计算的。就像我们在学校学习一样(见Long multiplication)。
例如:
// 17
// x 27
// ----
// 119
// + 34
// -----
// = 459
这是一个功能(应该进行优化),但会向您展示原理。
echo bn_mul('17', '27'), PHP_EOL; // 459
echo bn_mul('157', '27'), PHP_EOL; // 4239
echo bn_mul('1234', '6627'), PHP_EOL; // 8177718
echo bn_mul('23958233', '5830'), PHP_EOL; // 139676498390
echo bn_mul('290287121823', '290287121823'), PHP_EOL; // 84266613096281242843329
实现:
function bn_mul($n2, $n1) {
$l1 = strlen($n1);
$l2 = strlen($n2);
$rows = [];
for ($idx1 = $l1 - 1 ; $idx1 >= 0 ; $idx1--) {
// get digit
$d1 = substr($n1, $idx1, 1) ;
$carry = 0; // reset carry
$row = []; // store digit of $d1 x each digits of $n2
// prepend 0 (10 * num rows)
for ($x=0 ; $x<count($rows) ; $x++) $row[] = 0;
for ($idx2 = $l2 - 1 ; $idx2 >= 0 ; $idx2--) {
// get digit
$d2 = substr($n2, $idx2, 1) ;
// multiplication of digit 1 x digit 2 + current carry
$r = $d1 * $d2 + $carry;
$carry = 0;
// compute carry
if ($r >= 10) {
$carry = substr($r, 0, -1);
$r = substr($r, -1);
}
$row[] = $r ;
}
if ($carry) $row[] = $carry;
$rows[] = $row ;
}
// Sum digits of rows
$total = [] ;
$carry = 0 ;
for ($x=0;$x < count(end($rows)) ; $x++){
$tot = $carry;
$carry = 0;
foreach ($rows as $row){
if (isset($row[$x])) $tot += $row[$x] ;
}
while ($tot >= 10) {
$tot -= 10;
$carry++;
}
$total[$x] = $tot;
}
return strrev(implode($total));
}
答案 1 :(得分:0)
你应该记住,即使PHP不是类型安全的,背景中也有类型。
当您查找documentation时,您会发现,浮动点的精度最高可达14位。因此,所有尾随数字都被“切断”。幅度仍然存在,并且将以科学格式打印,但您无法真正知道14位数字的“低于”。因此,您尝试转换结果注定首先失败。
示例:
12345678910111213
^^^ get's cut off