JS整型的坑
昨天同事跟我说js在整型长度支持上有坑,我去查了一下确实是有些坑的。js对于数值的保存遵循IEEE 754 双精度浮点格式规范,采用了双精度存储,占用64bit。如图所示:
-
0到51位为尾数(也就是有效数)
-
52位到62位为指数。
如果使用无符号整数格式,则算术中使用的指数值是偏移的指数 - 对于IEEE 754 binary64情况,指数值1023表示实际零(即2 e - 1023为1, e必须是1023)。指数范围从-1022到+1023,因为-1023(全0)和+1024(全1)的指数是为特殊数字保留的。
-
最后一位为符号位,用来声明数值的符号,即正负。
那么可以发现,想保证结果无偏移的话只有e为1023,即有效数为 $$ 2*2^{52} = 2^{53} $$ 即js中长整型不超过
> Math.pow(2,53)
<· 9007199254740992
精度就不会丢失。坑啊(╯‵□′)╯︵┻━┻
Springboot中的处理
说一说我的处理方案吧,因为项目使用的fastjson,因此在网上看到的关于jackson的处理方式,诸如@JsonSerialize注解等方式都是不行的,使用SerializeFilter的话改动又太大,最后还是决定自己动手修改返回值类型吧。下面直接上代码:
package packagename.response;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import java.util.HashMap;
@RestControllerAdvice
public class ResponseHandler implements ResponseBodyAdvice {
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
//默认不进行拦截,返回值为false,拦截则返回true
return true;
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
//对body进行处理
if (body instanceof HashMap) {
HashMap<String, Object> finalJson = (HashMap<String, Object>) body;
finalJson.forEach((key, value) -> {
if (value instanceof Long) {
finalJson.put(key, String.valueOf(value));
}
});
}
return body;
}
}
如代码所示,body就是返回值内容,对body的处理就是遍历里面的value,将类型为Long的value转化为字符串再塞回去。OK,just it is.
结语
这个是这两天踩得一个小坑,重点其实不是处理部分,反而是了解了双精度的规范XD,里面关于数据偏移那部分的内容看得也是一知半解,如果内容中包含什么错误,也请路过的小伙伴给予指正,多谢~