雪花算法生成序列号精度丢失问题定位及解决方案

一、问题背景

雪花算法生成的id经过浏览器后id后几位全部变成"0000",导致列表展示后进入详情无法查询详情。

经dubbo服务调用,返回正常的id,经网关后查询日志也返回正常id,经Postmain调用也返回正常的id,经页面点击查询后查看列表信息,经谷歌浏览器开发工具Network查看,返回数据id的结尾已经变成"0000";

三、问题原因

Java中Long的取值范围为-9223372036854775808到9223372036854775807(即-2^64“ 到”2^64-1)

而JavaScript中的Number取值范围为-9007199254740992 到9007199254740991 (即-2^53 到2^53-1)

四、解决方案

在传的时候把Long转换成String类型

使用spring的Json解析器时使用@JsonSerialize(using = ToStringSerializer.class) 注解

@JsonSerialize(using = ToStringSerializer.class)

private Long id;

五、 延伸探究

为什么avaScript中的Number取值范围是-2^53 到2^53-1?

IEEE 754规定了四种表示浮点数值的方式:单精确度(32位)、双精确度(64位)、延伸单精确度(43比特以上,很少使用)与延伸双精确度(79比特以上,通常以80位实现)。

Number类型使用的便是其中的双精确度(64位)数据结构如下

Number类型的51-62位为指数位,63位为符号位,所以取值范围是-2^53 到2^53-1

复制来对 Number类型 相对官方的解释.

ECMAScript 中最有意思的数据类型或许就是 Number 了。Number 类型使用IEEE 754 格式表示整数和浮点值(在某些语言中也叫双精度值)。 ---红宝书

在 JavaScript 中, Number 是一种 定义为 64位双精度浮点型(double-precision 64-bit floating point format) (IEEE 754)的数字数据类型。 ---MDN

Number 类型使用IEEE 754 格式。

IEEE 754 格式

IEEE 754规定了四种表示浮点数值的方式:单精确度(32位)、双精确度(64位)、延伸单精确度(43比特以上,很少使用)与延伸双精确度(79比特以上,通常以80位实现)。

Number类型使用的便是其中的双精确度(64位)。

这张图就把结构说清了。

举个例子

  1. 十进制数值:10.25
  2. 转化为二进制 => 1010.01
  3. 规格化 => 1.01001 * 2^3
  4. 存储: 01001放在尾数位置,3放在指数位。指数位有11位,则移码是1023+3,为100...0010,移码参考这个IEEE754表示浮点数。整个表示为这样:

考虑能表示的最大值,就要看:

在固定位数时候所能表示的最大值。

指数位 移码最大值为11位1,原码最大值为10位1(原码最高位表示符号位),则y最大为1023,x最大表示52位1。即1.1111...1乘以 2^1023,即2^1023*(2-2^-52) 这个值也就是 Number.MAX_VALUE 的大小

最大安全数

什么叫最大安全整数?指的也就是这个常量Number.MAX_SAFE_INTEGER

现在考虑,我们看两个数2^53与2^53+1。

  • 2^53 我们尝试把它表示成二进制:1 53个0 ,规格化 1.0...00 * 2^53
  • 那2^53+1呢?我们尝试把它表示成二进制:1 52个0 1 ,标准化 1.0...01 * 2^53

问题来了,尾数都有53位,但只要52个空! 它的处理办法是 忽略第53位 ,因此这两个数在计算机中表示的结果一样!

2**53===2**53+1 //true 复制代码

猜你喜欢

转载自blog.csdn.net/u012921921/article/details/130980666
今日推荐