精度计算
发表于:2023-10-17 |

前言

我们都知道,计算机底层是二进制,而二进制是无法精确表示小数的,所以在计算的时候,会出现精度丢失的问题,这里我给出一个解决方案。

问题举例

比如我们的0.1+0.2在计算中会出现0.30000000000000004的情况。而不是我们认为的0.3,这是因为
在计算机中,浮点数一般采用 IEEE 754 标准进行表示和计算。按照该标准,浮点数通常由三个部分组成:符号位(S)、指数位(E)和尾数位(M)。具体来说,一个浮点数可以表示为:(-1)^S * M * 2^E。

对于十进制中的 0.1 和 0.2,它们在二进制中无法精确表示。转换成二进制后会出现无限循环的情况。因此,在计算机内部,这两个数会被近似表示。

当计算机进行浮点数加法时,会将参与运算的两个数统一调整为相同的指数,从而进行小数部分的相加。在这个过程中,可能会出现精度损失。

具体到 0.1 + 0.2 的运算中,0.1 转换为二进制后是个无限循环小数,近似值为 0.00011001100110011…(省略后续循环),而 0.2 转换为二进制后是个无限循环小数,近似值为 0.0011001100110011…(省略后续循环)。当这两个近似值进行相加时,结果是 0.010011001100110011…(省略后续循环)。

然而,计算机内部的存储空间是有限的,通常使用特定位数的二进制表示浮点数。在这个有限的存储空间中,只能保留一定精度的有效数字。因此,当计算机将上述近似值存储起来时,存储的实际值会更接近这个近似值。

所以,对于计算机来说,0.1 + 0.2 在存储和计算过程中会存在精度损失,最终结果可能会是一个近似值,而非精确的 0.3。这是浮点数运算在计算机中普遍面临的问题。在编程中,进行浮点数比较时,需要使用适当的误差范围进行判断,而非直接比较它们的值是否相等。

解决方案

将数据变成string进行计算

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
export const math = {
/**
* 加法
* @param {Number} a 加数
* @param {Number} b 加数
* @returns
*/
add(a, b) {
let m, n, x; // a的小数位数,b的小数位数,放大倍数
try {
m = a.toString().split(".")[1].length;
} catch (e) {
m = 0;
}
try {
n = b.toString().split(".")[1].length;
} catch (e) {
n = 0;
}
x = Math.max(m, n);
const transform = (num) => +num.toFixed(x).toString().replace(".", "");
return (transform(+a) + transform(+b)) / 10 ** x;
},
// 减法
accSub(a, b) {
return this.accAdd(a, -b);
},
// 乘法
multiply(a, b) {
let x = 0,
a_str = a.toString(),
b_str = b.toString();
try {
x += a_str.split(".")[1].length;
} catch (e) { }
try {
x += b_str.split(".")[1].length;
} catch (e) { }

return (+a_str.replace(".", "") * +b_str.replace(".", "")) / 10 ** x;
},
// 除法
divide(a, b) {
let x = 0,
y = 0,
a_str = a.toString(),
b_str = b.toString(),
a_mul = +a_str.replace(".", ""),
b_mul = +b_str.replace(".", "");
try {
x = a_str.split(".")[1].length;
} catch (e) { }
try {
y = b_str.split(".")[1].length;
} catch (e) { }
return (a_mul / b_mul) * 10 ** (y - x);
},
};

使用方法

1
2
import {math} from 'math.js'
math.add(0.1,0.2)

此时得到的结果就是0.3了。

结语

记录一点点,进步一点点。

上一篇:
判断文字是否溢出
下一篇:
获取屏幕比例