资讯专栏INFORMATION COLUMN

JS 的整型你懂了吗?

yuanxin / 2783人阅读

摘要:浮点数并不是能够精确表示范围内的所有数的,虽然浮点型的范围看上去很大。但其实浮点数在保存数字的时候做了规格化处理,以进制为例小数点前只需要保留位数对于二进制来说,小数点前保留一位,规格化后始终是节省了,这个并不需要保存。

JS 中的最大安全整数是多少?

JS 中所有的数字类型,实际存储都是通过 8 字节 double 浮点型 表示的。浮点数并不是能够精确表示范围内的所有数的, 虽然 double 浮点型的范围看上去很大: 2.23x10^(-308) ~ 1.79x10^308。 可以表示的最大整数可以很大,但能够精确表示,使用算数运算的并没有这么大。

它其实连这样的简单加法也会算错:

console.log(0.1 + 0.2)
//output: 0.30000000000000004

所以在 js 中能够安全使用的有符号 安全 大整数(注意这里是指能够安全使用,进行算数运算的范围),并不像其他语言在 64 位环境中那样是:

2^63 - 1;//9223372036854775807

而是

Math.pow(2, 53) - 1     // 9007199254740991

JS 的最大和最小安全值可以这样获得:

console.log(Number.MAX_SAFE_INTEGER); //9007199254740991
console.log(Number.MIN_SAFE_INTEGER); //-9007199254740991

通过下面的例子,你会明白为什么大于这个值的运算是不安全的:

var x = 9223372036854775807;
console.log(x === x + 1);// output: true
console.log(9223372036854775807 + 1000); //output: 9223372036854776000

这些运算都是错误的结果, 因为它们进行的都是浮点数运算会丢失精度。

为什么是这个值?

double 浮点数结构如下:

1 位符号位

11 位指数位

52 位尾数位

使用 52 位表示一个数的整数部分,那么最大可以精确表示的数应该是 2^52 - 1 才对, 就像 64 位表示整数时那样: 2^63 - 1 (去掉 1 位符号位)。 但其实浮点数在保存数字的时候做了规格化处理,以 10 进制为例:

20*10^2 => 2*10^3 //小数点前只需要保留 1 位数

对于二进制来说, 小数点前保留一位, 规格化后始终是 1.***, 节省了 1 bit,这个 1 并不需要保存。

如何处理大整数

Nodejs 越来越多的应用到后端的开发中, 不可避免的需要处理这样的溢出问题, 好在已经有很多优秀的第三方库来解决该问题:bignum、bigint。

大整数与数据库

Mysql 能处理的各个整形范围如下

//每种类型的第二行为无符号范围
TYPE         BYTE   MIN            MAX
TINYINT      1     -128            127
                                   255
SMALLINT     2    -32768          32767
                                  65535
MEDIUMINT    3    -8388608       8388607
                                 16777215
INT          4   -2147483648    2147483647
                                4294967295
BIGINT       8  -9223372036854775808    9223372036854775807
                                       18446744073709551615

BIGINT 就是 64 位整数, 一旦要处理的数据量超过了 BIGINT 能存储的范围,便要考虑使用字符串保存, 坏处是数字的算数运算需要通过应用程序使用大整数库来处理,不能依赖于数据库。

注: 常常看到 BIGINT(5) 或者 INT(10), 括号里的 5 或 10 只是表示展示宽度,并不影响数的精度范围和存储字节数,需要与 VARCHAR(100)或 DECIMAL(10,2)区分开

如何处理要求精度的运算?

当涉及财物类型的运算时, 位数一般不会溢出, 但精度要求回更高。数据库保存这些值时,需要使用 DECIMAL (NUMERIC 类型与之相同) 类型保存字段, 防止精度丢失。

小心位移操作

前面讨论了可以使用的安全整数范围,但在做位移操作时请小心:位移操作时,会将整数截断为 32 位有符号整型。也就是说超出这个范围的位移操作将会得到错误的值。例如:

196 << 24;// 输出: -1006632960 正确应为: 3288334336

位移的一些技巧可以戳 -> 这里

延伸阅读

代码之谜(四)- 浮点数(从惊讶到思考)

如果你有更好的关于浮点数相关学习资料, 希望能留言推荐!

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/85574.html

相关文章

  • JS 中的闭包是什么?

    摘要:大名鼎鼎的闭包面试必问。闭包的作用是什么。看到闭包在哪了吗闭包到底是什么五年前,我也被这个问题困扰,于是去搜了并总结下来。关于闭包的谣言闭包会造成内存泄露错。闭包里面的变量明明就是我们需要的变量,凭什么说是内存泄露这个谣言是如何来的因为。 本文为饥人谷讲师方方原创文章,首发于 前端学习指南。 大名鼎鼎的闭包!面试必问。请用自己的话简述 什么是「闭包」。 「闭包」的作用是什么。 首先...

    Enlightenment 评论0 收藏0
  • 【C语言基础之类型转换】

    摘要:类型转换的原则占用内存字节数少值域小的类型,向占用内存字节数多值域大的类型转换,以保证精度不降低。隐式类型转换隐式转换也称为自动转换,遵循一定的规则,由编译器自动完成。 ...

    jsliang 评论0 收藏0
  • JS基础篇--函数声明与定义,作用域,函数声明与表达式的区别

    摘要:在中,有四种方式可以让命名进入到作用域中按优先级语言定义的命名比如或者,它们在所有作用域内都有效且优先级最高,所以在任何地方你都不能把变量命名为之类的,这样是没有意义的形式参数函数定义时声明的形式参数会作为变量被至该函数的作用域内。 Scoping & Hoisting 例: var a = 1; function foo() { if (!a) { var ...

    TerryCai 评论0 收藏0
  • 深入理解Java整型类型:如何实现2+2=5?

    摘要:先看下这段神奇的代码执行结果那么到底做了什么神奇的事情呢先看代码所以这个例子其实包含了中整型类型的一个知识点。最后打印出来的值,实际上是的返回值。只有当输入参数不在区间内,才执行代码,基于输入参数创建一个新的实例。 先看下这段神奇的Java代码: public static void main(String[] args) throws Exception { doSom...

    aristark 评论0 收藏0
  • 关于php的printf系列函数的文章进行排错,虽已100%测试过。

    摘要:如果对应的变量中的值是个科学记数法的值,它会进行压缩然后插入到原字符串对应的符号位置,例如按照常规转换为如果使用它会压缩转换为。它取消掉了调用函数的参数,直接输出了使用方式相同,惟一不同的是它把存放对应变量的参数可以作为数组方式传入。 字符相关: %s - 对应的变量双引号中的值按照原样的内容插入到原字符串对应的%s符号位置。 %c - 参考百度百科->标准ASCII表相当于chr...

    nifhlheimr 评论0 收藏0

发表评论

0条评论

yuanxin

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<