Mat*_*rne 29 javascript variables types
在JavaScript中有几种不同的方法可以将浮点数转换为整数.我的问题是什么方法能提供最佳性能,最兼容,或被认为是最佳实践?
以下是我所知道的一些方法:
var a = 2.5;
window.parseInt(a); // 2
Math.floor(a); // 2
a | 0; // 2
Run Code Online (Sandbox Code Playgroud)
我相信那里还有其他人.建议?
来自Douglas Crockford的"Javascript:The Good Parts":
Number.prototype.integer = function () {
return Math[this < 0 ? 'ceil' : 'floor'](this);
}
Run Code Online (Sandbox Code Playgroud)
这样做是为每个Number对象添加一个方法.
然后你就可以这样使用它:
var x = 1.2, y = -1.2;
x.integer(); // 1
y.integer(); // -1
(-10 / 3).integer(); // -3
Run Code Online (Sandbox Code Playgroud)
显然双按位 - 不是最快的方法来放置一个数字:
var x = 2.5;
console.log(~~x); // 2
Run Code Online (Sandbox Code Playgroud)
曾经是这里的一篇文章,现在获得404:http://james.padolsey.com/javascript/double-bitwise-not/
Google已将其缓存: http://74.125.155.132/search?q=cache:wpZnhsbJGt0J:james.padolsey.com/javascript/double-bitwise-not/+double+bitwise+not&cd=1&hl=en&ct=clnk&gl=us
但Wayback Machine节省了一天!http://web.archive.org/web/20100422040551/http://james.padolsey.com/javascript/double-bitwise-not/
答案已经给出,但只是要清楚。
为此使用数学库。圆形、天花板或地板功能。
parseInt 用于将字符串转换为 int,这不是这里需要的
toFixed 用于将浮点数转换为字符串,也不是这里需要的
由于 Math 函数不会对字符串进行任何转换,因此它比任何其他错误的选择都要快。
“最佳”方式取决于:
浮动| 截断 | 地板 | 细胞| 近(半) ------+-------+-------+-------+-------------- +? | +? | +? | +? | +? +2.75 | +2 | +2 | +3 | +3 +2.5 | +2 | +2 | +3 | +3 +2.25 | +2 | +2 | +3 | +2 +0 | +0 | +0 | +0 | +0 南| 南| 南| 南| NaN -0 | -0 | -0 | -0 | -0 -2.25 | -2 | -3 | -2 | -2 -2.5 | -2 | -3 | -2 | -2 -2.75 | -2 | -3 | -2 | -3 -?| -?| -?| -?| -?对于浮点到整数的转换,我们通常期望“截断”
StringNumberString(默认基数 10)(在屏幕上) 只有在回答了这些考虑之后,我们才能考虑合适的方法和速度!
Number)都以由于这种格式存储1个符号位,11个指数位和第53位显著(“尾数”),我们可以说:只有 Number-值之间 ,并可以有一小部分。
换句话说:所有表示的正和负-值之间,以(几乎)(在该点格式调用它一天)已经整数(内部倒圆的,因为不存在的位向左表示剩余的分数和/或至少显著整数)。-252+252Number 2522(211/2=1024) Infinity
还有第一个“问题”:
您无法控制Number内置文字/字符串到浮点数转换的-results的内部舍入模式(舍入模式:IEEE 754-2008“舍入到最近,与偶数关联” ) 和内置算术运算(舍入模式:IEEE 754-2008“round-to-nearest”)。
例如:舍入并存储为:舍入并存储为:舍入并存储为:舍入并存储为:舍入并存储为:舍入并存储为:舍入并存储为:舍入并存储为:
252+0.25 = 4503599627370496.254503599627370496
252+0.50 = 4503599627370496.504503599627370496
252+0.75 = 4503599627370496.754503599627370497
252+1.25 = 4503599627370497.254503599627370497
252+1.50 = 4503599627370497.504503599627370498
252+1.75 = 4503599627370497.754503599627370498
252+2.50 = 4503599627370498.504503599627370498
252+3.50 = 4503599627370499.504503599627370500
为了控制舍入你Number需要一个小数部分(至少有一位来表示),否则 ceil/floor/trunc/near 返回你输入的整数。
为了正确地 ceil/floor/trunc a Number 最多 x 个有效的小数位数,我们只关心相应的最低和最高十进制小数值在四舍五入后是否仍会给我们一个二进制小数值(因此不会被限制或限制为下一个整数)。
因此,例如,如果您希望“正确”舍入(对于 ceil/floor/trunc)最多为 1 个有效小数位(x.1 to x.9),我们至少需要3 位(而不是 4 位)来给我们一个二进制小数值:
0.1更接近到比它和更接近比它。1/(23=8)=0.12500.91-1/(23=8)=0.8751
最多只有所有可表示的值具有不超过第一个有效十进制小数位(值到)的非零二进制分数。
2位小数、3位小数、4位小数、5位小数、6位小数、7位小数、8位小数、9位小数、10位小数、11位小数等。±2(53-3=50)x.1x.9±2(53-6=47)±2(53-9=44)±2(53-13=40)±2(53-16=37)±2(53-19=34)±2(53-23=30)±2(53-26=27)±2(53-29=24)±2(53-33=20)±2(53-36=17)
一个“安全整数”在JavaScript是一个整数:
±253±(253+1)这有效地定义了和之间 的(可安全表示的)整数的子集范围: -253+253
-(253 - 1) = -9007199254740991Number.MIN_SAFE_INTEGERto:(包含)
(自 ES6 起作为静态属性提供的常量)这两个新 ES6 常量的简单 polyfill:+(253 - 1) = +9007199254740991Number.MAX_SAFE_INTEGER
Number.MIN_SAFE_INTEGER || (Number.MIN_SAFE_INTEGER=
-(Number.MAX_SAFE_INTEGER=9007199254740991) //Math.pow(2,53)-1
);
Run Code Online (Sandbox Code Playgroud)
从 ES6 开始,还有一个免费的静态方法Number.isSafeInteger()可以测试传递的值是否属于类型Number并且是安全整数范围内的整数(返回布尔值true或false)。
注意:也将返回falsefor: NaN,Infinity并且很明显String(即使它代表一个数字)。
填充示例:
Number.isSafeInteger || (Number.isSafeInteger = function(value){
return typeof value === 'number' &&
value === Math.floor(value) &&
value < 9007199254740992 &&
value > -9007199254740992;
});
Run Code Online (Sandbox Code Playgroud)
ECMAScript 2015 / ES6 提供了一种新的静态方法Math.trunc()
来将浮点数截断为整数:
返回数字 x 的整数部分,删除所有小数位。如果 x 已经是整数,则结果为 x。
或者更简单(MDN):
与其他三种数学方法:
Math.floor(),Math.ceil()和 不同Math.round(),其Math.trunc()工作方式非常简单明了:
只需截断点及其后面的数字,无论参数是正数还是负数。
我们可以进一步解释(和 polyfill)Math.trunc():
Math.trunc || (Math.trunc = function(n){
return n < 0 ? Math.ceil(n) : Math.floor(n);
});
Run Code Online (Sandbox Code Playgroud)
注意,上面的填充工具的有效载荷可以潜在地可以更好地由发动机预优化相比:
Math[n < 0 ? 'ceil' : 'floor'](n);
用法:Math.trunc(/* Number or String */)
输入:(整数或浮点数)Number(但会很乐意尝试将字符串转换为数字)
输出:(整数)Number(但会很乐意尝试在字符串上下文中将数字转换为字符串)
范围:-2^52到+2^52(超出此范围)我们应该期待“舍入误差”(以及在某些时候科学/指数符号)简单明了,因为我们Number在 IEEE 754 中的输入已经失去了小数精度:因为±2^52到之间的数字±2^53已经是内部四舍五入的整数(例如4503599627370509.5,内部已经表示为4503599627370510)并且超出±2^53整数也失去精度(2的幂))。
浮点数到整数的转换,通过减去除数的余数( %) 1:
示例:(result = n-n%1或n-=n%1)
这也应该截断浮点数。由于求余运算符具有更高的优先级比减法,我们有效地得到:(n)-(n%1)。
对于正数很容易看出,这层楼的价值:(2.5) - (0.5) = 2,
负数这ceils值:(-2.5) - (-0.5) = -2(因为--=+这样(-2.5) + (0.5) = -2)。
由于输入和输出是与 ES6 (或它的 polyfill)相比,Number我们应该获得相同的有用范围和输出Math.trunc()。
注意:艰难我担心(不确定)可能存在差异:因为我们正在对原始数字(浮点数)和第二个派生数字(分数)进行算术运算(内部使用舍入模式“nearTiesEven”(又名银行家的舍入)) ) 这似乎会导致复合 digital_representation 和算术舍入错误,因此可能最终返回一个浮点数..
通过(ab-)使用按位运算将浮点数转换为整数:
这个作品由内部迫使(浮点)Number转化率(截断和溢出)到一个符号的32位整数值(二进制补码)通过使用按位操作上的Number(并且结果是转换回(浮点)Number,其保持只是整数值)。
同样,输入和输出是Number(再次从字符串输入到数字和数字输出到字符串的静默转换)。
更重要的困难(通常被遗忘和不解释):
取决于按位运算和数字的符号,有用的范围将被限制在:
-2^31到+2^31(像~~num或num|0或num>>0)或 0到+2^32(num>>>0)之间。
这应该通过以下查找表(包含所有“关键”示例)进一步澄清:
| | n>>0 或 n<<0 或 | n>>>0 | n < 0 ? -(-n>>>0) : n>>>0
| n|0 或 n^0 或 ~~n | |
| 或 n&0xffffffff | |
----------------------------+--------------------+- ------------+----------------------------
+4294967298.5 = (+2^32)+2.5 | +2 | +2 | +2
+4294967297.5 = (+2^32)+1.5 | +1 | +1 | +1
+4294967296.5 = (+2^32)+0.5 | 0 | 0 | 0
+4294967296 = (+2^32) | 0 | 0 | 0
+4294967295.5 = (+2^32)-0.5 | -1 | +4294967295 | +4294967295
+4294967294.5 = (+2^32)-1.5 | -2 | +4294967294 | +4294967294
等等... | 等等... | 等等... | 等等...
+2147483649.5 = (+2^31)+1.5 | -2147483647 | +2147483649 | +2147483649
+2147483648.5 = (+2^31)+0.5 | -2147483648 | +2147483648 | +2147483648
+2147483648 = (+2^31) | -2147483648 | +2147483648 | +2147483648
+2147483647.5 = (+2^31)-0.5 | +2147483647 | +2147483647 | +2147483647
+2147483646.5 = (+2^31)-1.5 | +2147483646 | +2147483646 | +2147483646
等等... | 等等... | 等等... | 等等...
+1.5 | +1 | +1 | +1
+0.5 | 0 | 0 | 0
0 | 0 | 0 | 0
-0.5 | 0 | 0 | 0
-1.5 | -1 | +4294967295 | -1
等等... | 等等... | 等等... | 等等...
-2147483646.5 = (-2^31)+1.5 | -2147483646 | +2147483650 | -2147483646
-2147483647.5 = (-2^31)+0.5 | -2147483647 | +2147483649 | -2147483647
-2147483648 = (-2^31) | -2147483648 | +2147483648 | -2147483648
-2147483648.5 = (-2^31)-0.5 | -2147483648 | +2147483648 | -2147483648
-2147483649.5 = (-2^31)-1.5 | +2147483647 | +2147483647 | -2147483649
-2147483650.5 = (-2^31)-2.5 | +2147483646 | +2147483646 | -2147483650
等等... | 等等... | 等等... | 等等...
-4294967294.5 = (-2^32)+1.5 | +2 | +2 | -4294967294
-4294967295.5 = (-2^32)+0.5 | +1 | +1 | -4294967295
-4294967296 = (-2^32) | 0 | 0 | 0
-4294967296.5 = (-2^32)-0.5 | 0 | 0 | 0
-4294967297.5 = (-2^32)-1.5 | -1 | +4294967295 | -1
-4294967298.5 = (-2^32)-2.5 | -2 | +4294967294 | -2
注 1:最后一列已将范围扩展0到-4294967295使用(n < 0 ? -(-n>>>0) : n>>>0).
注 2:按位引入了它自己的转换开销(s)(严重性 vsMath取决于实际实现,因此按位可能更快(通常在较旧的历史浏览器上))。
String开头,parseInt(/*String*/, /*Radix*/)那么将其解析为 integer 将是一个合适的选择Number。parseInt()也会截断(对于正数和负数)。Math方法所解释的那样。
最后,如果您有 aString并期望 aString作为输出,您还可以截断小数点和分数(与 IEEE 754 双精度浮点 ( ±2^52)相比,这也为您提供了更大的准确截断范围)!
例如,如果您想从零开始舍入(又名舍入到无穷大),您可以修改Math.trunc()polyfill,例如:
Math.intToInf || (Math.intToInf = function(n){
return n < 0 ? Math.floor(n) : Math.ceil(n);
});
Run Code Online (Sandbox Code Playgroud)