javascript 32位整数乘法模拟
我只想乘以int,就像32位整数一样,带溢出 有些文章很容易喜欢按位操作javascript 32位整数乘法模拟,javascript,Javascript,我只想乘以int,就像32位整数一样,带溢出 有些文章很容易喜欢按位操作 function add32bit( a, b ) { return (a+b)|0; } 就这样 function mul32bit( a, b ) { return (a*b)|0; } 但这不是工作 在32位整数系统中,允许整数溢出 计算 12312311 * 1231231211 = -236858179 但是使用javascript (12312311 * 1231231211)|0 = -
function add32bit( a, b )
{
return (a+b)|0;
}
就这样
function mul32bit( a, b )
{
return (a*b)|0;
}
但这不是工作
在32位整数系统中,允许整数溢出
计算
12312311 * 1231231211 = -236858179
但是使用javascript
(12312311 * 1231231211)|0 = -236858180
有一种方法可以精确计算。解决方案(?)
根据Richie Frame的提示,我尝试使用编写一个函数,将两个整数相乘,并将结果作为有符号32位整数返回
// base algorithm from: https://en.wikipedia.org/wiki/Karatsuba_algorithm
// modified to discard values unneccessary for 32-Bit-operations
function int32_mul(x, y)
{
// We use B = 2 and m = 16, because it will make sure that we only do multiplications with
// 16 Bit per factor so that the result must have less than 32 Bit in total (which fits well
// into a double).
var bm = 1 << 16;
x0 = x % bm;
x1 = (x - x0) / bm;
y0 = y % bm;
y1 = (y - y0) / bm;
// z1 + z0. We can discard z2 completely as it only contains a value out of our relevant bounds.
// Both z1 and z0 are 32 Bit, but we shift out the top 16 Bit of z1.
return (((x1 * y0 + x0 * y1) << 16) + (x0 * y0)) | 0;
}
Javascript对所有计算(甚至是整数计算)使用双精度。通过以上测试,我得出结论,double不能具有15159301582738621
的值
这是因为浮点数据类型(如float(32位)、double(64位)和quad(128位)是如何工作的。基本上,它们不存储精确的值,而是以x*2^y
的形式存储值的x
和y
值,这使它们能够存储非常大的值和非常小的值。我们(人类)过去对于非常大的数字和非常小的数字都有类似的语法,例如十亿的1e9
,或者1e-5
的0.00001
,而e
是*10^
的快捷方式
现在假设您计算10001*10001
,这显然是100020001
,但假设您只能存储5位数字和一个指数。要存储结果,您必须对其进行近似,并使用例如1.0002e8
或10002e4
。正如你所看到的,你必须忘记最后的1。事实上,你的例子中双倍的问题非常相似,只是规模更大,基数是2,而不是10
最后两个
printf
语句证明double不能保存值15159301582738621
,这是示例计算的精确结果。如果您尝试使用12312311*1231231212
(第二个数字的末尾是2,而不是1),您会发现并非此范围内的所有数字都不能存储为双精度,因为该计算方法可以很好地用于您的函数。能否显示将传递给函数的值以及预期的结果?请出示你要找的Karatsuba乘法
var tests = [
[ 0, 0, 0 ],
[ 0, 1, 0 ],
[ 1, 1 << 8, 256 ],
[ 1, 1 << 16, 65536 ],
[ 1, 1 << 24, 16777216 ],
[ 1, 0x7fffffff, 2147483647 ],
[ 1, 0x80000000, -2147483648 ],
[ 1, 0xffffffff, -1 ],
[ 2, 1 << 8, 512 ],
[ 2, 1 << 16, 131072 ],
[ 2, 1 << 24, 33554432 ],
[ 2, 0x80000000, 0 ],
[ 2, 0x7fffffff, -2 ],
[ 2, 0xffffffff, -2 ],
[ 256, 256, 65536 ],
[ 65536, 65536, 0 ],
[ -2, 2, -4 ],
[ -65536, 65536, 0 ],
[ -2, -2, 4 ],
[ -2147483648, 1, -2147483648 ],
[ -2147483649, 1, 2147483647 ],
[ 12312311, 1231231211, -236858179 ],
];
for (var i = 0; i < tests.length; ++i)
{
var test = tests[i];
if (int32_mul(test[0], test[1]) !== test[2])
{ console.log(test[0], '*', test[1], '!==', test[2]); }
}
#include <stdio.h>
#include <stdint.h>
int main(void) {
printf("%d\n", (int32_t)(12312311L * 1231231211L));
printf("%llu\n", (uint64_t)12312311L * 1231231211L);
printf("%.32f\n", 12312311. * 1231231211.);
printf("%.8f\n", 15159301582738621.);
return 0;
}
-236858179
15159301582738621
15159301582738620.00000000000000000000000000000000
15159301582738620.00000000