调整计算精度

问题由来:js 数字存储采用 IEEE754 标准,该标准用 64 位二进制数存储一个浮点数,即一个数字占用的内存是 8bytes,因此在存储一个无限大的数字时就会存在精度损失。对于像 0.1 这样的浮点数来说,无法用二进制的方式精确表示,这是由计算方式本身决定的,因此这部分浮点数的存储精度丢失是必然的,和语言、存储方式、内存大小没有关系。当然,像 0.5 这种可以用二进制精确表示,并且大小不超过 2** 53 - 1 的浮点数是可以精确存储的。IEEE754 的存储方式是,最高位是符号位,0 表示正,1表示负;接下来是 11 位指数位;接下来是 52 位小数位。二进制的科学计数法,它的整数部分固定是 1,所以 1 个整数位加上 52 的小数位,最大可以表示 2**53 - 1,因此即使是整数,如果超出这个范围,存储精度也是要损失的。

思路:刚才说一个无穷数的存储是有问题的,如果我们把浮点数当作整数计算,计算完成后再转换为字符串类型的小数存储是不是就可以了。

实现:

 1 function add(a, b) {
 2     a = a.toString(),
 3         b = b.toString();
 4     const r0 = a.includes('.') ? a.length - (a.indexOf('.') + 1) : ((a += '.'), 0),
 5         r = b.includes('.') ? b.length - (b.indexOf('.') + 1) : ((b += '.'), 0);
 6 
 7     if (r0 > r) {
 8         b += '0'.repeat(r0 - r);
 9     }
10 
11     if (r > r0) {
12         a += '0'.repeat(r - r0);
13     }
14 
15     return (+a.replace('.', '') + +b.replace('.', '')) / 10 ** Math.max(r0, r);
16 }
17 
18 function sub(a, b) {
19     return add(a, -b);
20 }
21 
22 function mul(a, b) {
23     a = a.toString(),
24         b = b.toString();
25     const r0 = a.includes('.') ? a.length - (a.indexOf('.') + 1) : ((a += '.'), 0),
26         r = b.includes('.') ? b.length - (b.indexOf('.') + 1) : ((b += '.'), 0);
27 
28     if (r0 > r) {
29         b += '0'.repeat(r0 - r);
30     }
31 
32     if (r > r0) {
33         a += '0'.repeat(r - r0);
34     }
35 
36     return (+a.replace('.', '') * +b.replace('.', '')) / (10 ** Math.max(r0, r)) ** 2;
37 }
38 
39 function div(a, b) {
40     a = a.toString(),
41         b = b.toString();
42     const r0 = a.includes('.') ? a.length - (a.indexOf('.') + 1) : ((a += '.'), 0),
43         r = b.includes('.') ? b.length - (b.indexOf('.') + 1) : ((b += '.'), 0);
44 
45     if (r0 > r) {
46         b += '0'.repeat(r0 - r);
47     }
48 
49     if (r > r0) {
50         a += '0'.repeat(r - r0);
51     }
52 
53     return +a.replace('.', '') / +b.replace('.', '');
54 }
55 
56 export {
57     add,
58     sub,
59     mul,
60     div
61 };

 

posted @ 2023-06-22 01:26  万物有序  阅读(34)  评论(0编辑  收藏  举报