【JS】数值精度缺失问题解决方案

方法一:
保留字符串类型,传给后端

方法二:
如果涉及到计算,用以下方法

// 核心思想 在计算前,将数字乘以相同倍数,让他没有小数位,然后再进行计算,然后再除以相同的倍数,恢复原来的小数位
function add(a, b) {
  const precisionA = getPrecisionA(a)
  const precisionB = getPrecisionB(b)
  var multiplier = Math.pow(10, Math.max(precisionA, precisionB))
  return (a * multiplier + b * multiplier) / multiplier
}

function getPrecisionA() {
  if (num.toString().indexOf('e') !== -1) {
    var precision = num.toString().split('e-')[1]
    return parseInt(precision, 10)
  }

  var decimalPart = num.toString().split('.')[1]
  return decimalPart ? decimalPart.length : 0
}

以下是完整函数:

/**
 * 把递归操作扁平迭代化
 * @param {number[]} arr 要操作的数字数组
 * @param {function} operation 迭代操作
 * @private
 */
function iteratorOperation(arr,operation){
const [num1,num2,...others]=arr;
let res=operation(num1,num2)
other.forEach((num)=>{
res=operation(res,num)
})
return res
}

/**
 * 返回小数部分的长度
 * @private
 * @param {*number} num Input number
 */
 function digitLength(num){
 // 指数部分通常是用字母 "e" 或 "E" 后跟一个整数表示
 const eSplit=num.toString().spilt(/[eE]/);
 const len=(eSplit[0].split('.')[1] || '').length - +(eSplit[1] || 0);
 return len>0?len:0;
}

/**
 * 把小数转成整数,如果是小数则放大成整数
 * @private
 * @param {*number} num 输入数
 */
function float2Fixed(num){
if(num.toString().indexOf('e')===-1){
return Number(num.toString().replace('.',''))
}
const dLen = digitLength(num);
  return dLen > 0 ? strip(Number(num) * Math.pow(10, dLen)) : Number(num);
}

/**
 * 把错误的数据转正
 * @private
 * @example strip(0.09999999999999998)=0.1
 */
 function strip(num,precision=15){
 // toPrecision将数字转换为具有指定有效数字位数的字符串表示形式
 // parseFloat 将字符串转为浮点数
  return +parseFloat(Number(num).toPrecision(precision));
 }

/**
 * 高精度乘法
 */
 function times(...nums){
   if (nums.length > 2) {
    return iteratorOperation(nums, times);
  }
  const [num1, num2] = nums;
  const num1Changed = float2Fixed(num1);
  const num2Changed = float2Fixed(num2);
  const baseNum = digitLength(num1) + digitLength(num2);
  const leftValue=num1Changed * num2Changed
  // 并返回底数的指数次幂
  return  leftValue/ Math.pow(10, baseNum);
  
 }

/**
 * 高精度加法
 */
 function plus(...nums){
if(nums.length>2){
return iteratorOperation(nums, plus)
}
const [num1,num2]=nums
// 取最大的小数位
// Math.pow 函数计算以 10 为底、指数为两个数字小数部分长度的最大值的幂次方
const baseNum=Math.pow(10,Math.max(digitLength(num1), digitLength(num2)))
// 把小数转为整数再计算
 return (times(num1, baseNum) + times(num2, baseNum)) / baseNum;
}

/**
 * 高精度减法
 * @export
 */
 function minus(...nums) {
  if (nums.length > 2) {
    return iteratorOperation(nums, minus);
  }

  const [num1, num2] = nums;
  const baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2)));
  return (times(num1, baseNum) - times(num2, baseNum)) / baseNum;
}

/**
 * 高精度除法
 * @export
 */
function divide(...nums) {
  if (nums.length > 2) {
    return iteratorOperation(nums, divide);
  }

  const [num1, num2] = nums;
  const num1Changed = float2Fixed(num1);
  const num2Changed = float2Fixed(num2);
  checkBoundary(num1Changed);
  checkBoundary(num2Changed);
  // 重要,这里必须用strip进行修正
  return times(num1Changed / num2Changed, strip(Math.pow(10, digitLength(num2) - digitLength(num1))));
}
### MyBatis-Plus 精度缺失问题解决方案 #### 问题背景: 当使用 MyBatis-Plus 向后端传递 ID(如由雪花算法生成的 ID)时,前端和后端之间的精度可能因数据类型限制而发生差异。前端 JavaScript 中 `Number` 类型的精度通常为 16 位,而 MySQL 数据库的 `Long` 类型默认为 64 位。这种情况下,若前端传输的数据长度超过了前端支持的范围,则可能导致精度损失。 #### 分析原因: 以雪花算法为例,它产生的 ID 是一个具有时间戳、工作机器标识以及序列号组成的长整型数字,长度可达 64 位。然而,在前端(尤其是 JavaScript 环境下),接收此 ID 并进行处理时,由于 `Number` 类型的限制,可能会导致高位信息丢失,从而影响后续基于该 ID 的业务逻辑执行。 #### 解决方案: 1. **转换数据类型**:前端接收数据后,可以将 `String` 类型的 ID 转换为 `BigInt` 或者自定义大数类来存储和操作,避免 `Number` 类型的精度限制。 示例代码: ```javascript const idStr = '1234567890123456'; let bigIntId = BigInt(idStr); // 使用 BigInt 进行精确计算 ``` 2. **后端接收与验证**:在后端接口中,接收参数时应明确声明接受的是 `BigInteger` 类型或其他适合大数值的操作类型,同时进行相应的验证处理,确保接收到的数据不会因为类型不匹配而导致错误。 示例 Java 接口: ```java @PostMapping("/process-id") public ResponseEntity<String> processId(@RequestBody BigInteger id) { // 处理逻辑 return ResponseEntity.ok("ID processed successfully"); } ``` #### 总结: 解决精度缺失的关键在于明确数据类型需求并在前端和后端之间保持一致性的管理策略。前端可以通过使用大数类库(如 `BigInt`)来避免精度损失,而后端则需采用合适的数据类型处理和验证机制,确保数据的完整性和准确性。 --- ## 相关问题: 1. 当在 MyBatis-Plus 应用场景中遇到精度丢失问题时,如何判断是前端还是后端的问题导致的? 2. 如何在 MyBatis-Plus 中配置数据类型以适应大数值的需求? 3. 在使用雪花算法生成的 ID 时,前端应该如何安全地将这些 ID 传递给后端,以防止精度损失?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值