前端接收后端数据时,遇到精度丢失的问题_前端数字精度丢失

前言

之前项目开发过程中遇到过前端接收后端数据时,遇到精度丢失的问题。当时进行了问题记录,本篇博客针对于这个问题进行问题原因并进行多种方式解决这个问题。

问题原因

前端接收后端返回的数据时出现精度丢失问题,通常是因为在数据传输过程中,数据类型被转换为了 JavaScript 中的 Number 类型,而 JavaScript 的 Number 类型有一定的精度限制,无法精确表示一些较大或较小的数值,从而导致精度丢失。

JavaScript 中的 Number 类型可以表示的数字范围是 -9007199254740991 到 9007199254740991,即在 2 的 53 次方以内的整数和小数,超过这个范围的数字可能会失去精度或被表示为特殊的 Infinity 或 NaN 值。这是由于 JavaScript 中的 Number 类型采用的是 IEEE 754 标准的双精度浮点数表示法,使用 64 位二进制格式存储数字,其中 1 位符号位、11 位指数位和 52 位尾数位。因此,JavaScript 中的 Number 类型能够存储的有效数字位数为 52 位,即最多可以精确表示 15 位十进制数字。

如何解决

  1. 使用字符串类型传递:将后端生成的 ID 转换成字符串类型后再传递给前端,这样可以避免浮点数精度丢失的问题。
  2. 在前端进行精度处理:在前端接收到 ID 后,可以使用一些 JavaScript 库来进行高精度计算和处理,例如 decimal.js、bignumber.js 等,这样可以避免浮点数精度丢失的问题。
  3. 前后端统一使用相同的算法:可以尝试使用前后端都支持的算法来生成全局唯一 ID,这样可以保证前后端生成的 ID 是一致的,避免精度丢失的问题。

需要注意的是,如果精度丢失的问题比较严重,可能会影响到系统的正确性,因此需要根据实际情况选择适合的解决方法。

解决示例

后端解决方式

在对应的实体属性上添加注解:

@JsonSerialize(using = com.fasterxml.jackson.databind.ser.std.ToStringSerializer.class)

@JsonSerialize 注解用于指定在将 Java 对象序列化为 JSON 字符串时使用的序列化器,其中
using 属性用于指定序列化器的实现类。在这个例子中,
using 属性指定为
com.fasterxml.jackson.databind.ser.std.ToStringSerializer.class,即使用 Jackson 序列化库中的
ToStringSerializer 类来将 Java 对象的值序列化为字符串类型的 JSON 值。

具体来说,在这个例子中,ToStringSerializer 类实现了将 Java 对象的值序列化为字符串类型的 JSON 值的功能。例如,如果 Java 对象的一个属性是 Long 类型,使用默认的序列化方式时,该属性的值会被序列化为一个数字类型的 JSON 值。但是使用 ToStringSerializer 类时,该属性的值会被序列化为一个字符串类型的 JSON 值,即将该属性的值转换为字符串类型后再进行序列化。
使用 ToStringSerializer 类的主要作用是将 Java 对象中的某些属性序列化为字符串类型的 JSON 值,这通常用于解决一些精度丢失或溢出等问题。例如,在 Java 中,当使用 double 或 float 类型来表示一个非常大或非常小的数时,可能会出现精度丢失或溢出的问题,这时可以使用 ToStringSerializer 类将该属性的值转换为字符串类型后再进行序列化,避免精度问题。

示例:

@JsonSerialize(using = com.fasterxml.jackson.databind.ser.std.ToStringSerializer.class)
//解决雪花算法生成后,前端接收后缺失精度问题
private BigInteger id;

前端进行处理

将数字121212121211212564(17位)使用 decimal.js 库在前端进行精度处理的示例:

  1. 安装 decimal.js 库:
npm install decimal.js


### 性能优化

1.webpack打包文件体积过大?(最终打包为一个js文件)  

2.如何优化webpack构建的性能  

3.移动端的性能优化  

4.Vue的SPA 如何优化加载速度  

5.移动端300ms延迟  

6.页面的重构

**所有的知识点都有详细的解答,我整理成了280页PDF《前端校招面试真题精编解析》。**



![](https://img-blog.csdnimg.cn/20210323221732119.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2h1Z28yMzM=,size_16,color_FFFFFF,t_70)

![](https://img-blog.csdnimg.cn/20210323221747467.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2h1Z28yMzM=,size_16,color_FFFFFF,t_70)
<think>好的,我现在需要帮用户找到C++实现高精度加法的示例代码。用户提到了三个引用,我需要先仔细看看这些引用内容。 首先,引用[1]提供了一个C++的高精度加法函数,使用vector来存储数字,并且按位相加处理进位。看起来这个函数可能处理的是逆序存储的数字,因为通常在处理高精度加法,会从低位开始相加,所以可能需要将字符串反转存储到vector中。不过代码中没有显示输入处理的部分,用户可能需要自己处理字符串转换到vector的过程。 引用[2]提到高精度加法是用字符串输入的,并且步骤包括输入字符串、倒序存入数组、按位相加处理进位。这里可能涉及到将字符串转换为数字数组,并且可能需要倒序存储,方便从低位开始计算。但具体的代码示例没有给出,只有输入部分的伪代码。 引用[3]则提到用数组实现高精度加法,并附有源代码链接,但用户可能无法直接访问链接,所以需要根据已有的信息整合代码。 用户的需求是获取C++的高精度加法示例代码。结合这三个引用,我需要综合出一个完整的示例,包括字符串输入、转换到数组或vector、相加处理进位,以及结果输出。 现在需要考虑如何将字符串转换为数字数组或vector。通常的做法是将字符串逆序存储,这样每一位对应数组的一个元素,比如字符串"123"转换为数组[3,2,1],这样在相加可以从索引0开始处理每一位的加法。 然后,相加的过程需要处理进位,每一位相加后取模10得到当前位的值,除以10得到进位。循环处理每一位,直到所有位处理完毕,并且最后的进位不为零需要添加到结果中。 引用[1]中的代码使用了vector<int>,并且在循环中处理两个数的相加,进位变量t在每次迭代中累加。这可能是一个正确的实现,但需要确认输入的两个vector是否已经逆序存储。例如,在函数add中,参数是vector<int>&a和b,可能假设它们已经是逆序存储的数字,每一位对应vector的一个元素。 因此,完整的代码应该包括: 1. 输入两个字符串s1和s2。 2. 将字符串转换为vector<int>,逆序存储每个字符对应的数字。 3. 调用add函数进行相加。 4. 处理结果vector,逆序输出得到最终的和。 现在需要补全这些步骤的代码。例如,将字符串转换为vector的部分,需要遍历字符串的每个字符,将其转换为int,并逆序存入vector。例如,字符串s1是"123",转换后的vector应该是[3,2,1]。 在引用[1]的代码中,主函数部分可能缺失,需要补充这部分。例如,读取输入字符串,转换到vector,调用add函数,然后处理结果。 可能的示例代码如下: 首先读取字符串s1和s2,然后将它们转换为vector<int>,逆序存储,每个字符减去'0'得到数字。然后调用add函数,得到的结果vector是逆序存储的,需要逆序输出。 需要注意处理前导零的情况,比如输入"000123"应该转换为321,但结果输出需要去掉前面的零。不过在相加过程中,结果可能不会有前导零,除非结果为0,这需要保留一个零。 另外,在引用[1]的代码中,循环条件是i < a.size() || i < b.size(),这会处理所有位,直到两个数都被处理完。进位t在循环结束后如果大于0会被添加到结果中。例如,如果最后还有进位,比如9+9=18,进位1会被加入结果。 现在,整合这些步骤写出完整的代码,并确保正确性。例如: #include <iostream> #include <string> #include <vector> using namespace std; vector<int> add(vector<int>& a, vector<int>& b) { vector<int> ret; int t = 0; for (int i = 0; i < a.size() || i < b.size(); i++) { if (i < a.size()) t += a[i]; if (i < b.size()) t += b[i]; ret.push_back(t % 10); t /= 10; } if (t) ret.push_back(t); return ret; } int main() { string s1, s2; cin >> s1 >> s2; vector<int> a, b; for (int i = s1.size() - 1; i >= 0; i--) a.push_back(s1[i] - '0'); for (int i = s2.size() - 1; i >= 0; i--) b.push_back(s2[i] - '0'); auto res = add(a, b); for (int i = res.size() - 1; i >= 0; i--) cout << res[i]; cout << endl; return 0; } 这样,代码就完成了输入字符串,转换到逆序vector,相加处理进位,最后逆序输出结果。这个应该符合用户的需求,并且参考了引用中的代码结构。 需要验证一下这个代码是否正确。例如,输入"123"和"456",转换为a=[3,2,1],b=[6,5,4],相加后得到每一位的和: i=0: 3+6=9, t=9%10=9, t=0 i=1: 2+5=7, t=7%10=7, t=0 i=2: 1+4=5, t=5%10=5, t=0 结果ret是[9,7,5],逆序输出579,正确。 如果输入"999"和"2",a=[9,9,9], b=[2]。相加: i=0:9+2=11 → ret.push(1), t=1 i=1:9 → t=1+9=10 → push(0, t=1) i=2:9 → t=1+9=10 → push(0, t=1) 最后t=1 → push(1) ret=[1,0,0,1],逆序输出1001,即1001,正确。 所以这段代码应该可以正确处理进位的情况。 用户可能需要这个完整的示例,所以现在需要将代码整理出来,并解释关键步骤,比如字符串反转存储,按位相加处理进位,结果反转输出。同需要注意代码的正确性和可读性。</think>以下是用C++实现高精度加法的完整代码示例及分步说明: ```cpp #include <iostream> #include <string> #include <vector> using namespace std; // 高精度加法核心算法 vector<int> add(vector<int>& a, vector<int>& b) { vector<int> result; int carry = 0; // 进位标志 for (int i = 0; i < a.size() || i < b.size(); ++i) { if (i < a.size()) carry += a[i]; // 取a的第i位 if (i < b.size()) carry += b[i]; // 取b的第i位 result.push_back(carry % 10); // 存储当前位计算结果 carry /= 10; // 计算进位值 } if (carry) result.push_back(carry); // 处理最高位进位 return result; } int main() { string num1, num2; cin >> num1 >> num2; // 将字符串逆序存储为数字数组(个位在前) vector<int> a, b; for (int i = num1.size()-1; i >= 0; --i) a.push_back(num1[i] - '0'); for (int i = num2.size()-1; i >= 0; --i) b.push_back(num2[i] - '0'); // 执行加法运算 auto sum = add(a, b); // 逆序输出结果(从最高位到个位) for (int i = sum.size()-1; i >= 0; --i) { cout << sum[i]; } return 0; } ``` ### 关键实现步骤说明 1. **输入处理**:通过字符串接收超长数字输入,避免数值溢出问题[^2] 2. **数据存储**:将字符串逆序转换为`vector<int>`,便于从个位开始计算 - 例如输入`"12345"`转换为`[5,4,3,2,1]` 3. **核心算法**: - 按位相加并处理进位,间复杂度$O(n)$ - 使用`carry`变量同记录当前位和与进位值 4. **结果输出**:将结果数组逆序输出,还原为正常数字顺序 ### 示例运行 输入: ``` 9999999999999999999 1 ``` 输出: ``` 10000000000000000000 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值