为什么0乘以截断小数?

voi*_*hos 20 javascript numbers operators bit-shift bitwise-operators

我最近发现了这段JavaScript代码:

Math.random() * 0x1000000 << 0
Run Code Online (Sandbox Code Playgroud)

我知道第一部分只是生成0到0x1000000(== 16777216)之间的随机数.

但第二部分似乎很奇怪.执行0位移位有什么意义?我不认为它会做任何事情.然而,经过进一步调查,我注意到0的偏移似乎截断了数字的小数部分.此外,无论是右移,左移,还是无符号右移,都无关紧要.

> 10.12345 << 0
10
> 10.12345 >> 0
10
> 10.12345 >>> 0
10
Run Code Online (Sandbox Code Playgroud)

我用Firefox和Chrome测试过,行为是一样的.那么,这个观察的原因是什么?它只是JavaScript的细微差别,还是也出现在其他语言中?我以为我理解了位移,但这令我感到困惑.

Ry-*_*Ry- 20

你是对的; 它用于截断值.

之所以>>有效,是因为它只能在32位整数上运行,因此值会被截断.(它也常用于像这样的情况,而不是Math.floor因为按位运算符具有较低的运算符优先级,所以你可以避免乱七八糟的括号.)

并且由于它仅在32位整数上运行,因此它也相当于具有0xffffffff舍入后的掩码.所以:

0x110000000      // 4563402752
0x110000000 >> 0 // 268435456
0x010000000      // 268435456
Run Code Online (Sandbox Code Playgroud)

但这不是预期行为的一部分,因为Math.random()它将返回0到1之间的值.

此外,它也是一样的| 0,这是更常见的.

  • 你能详细解释一下为什么“&gt;&gt;”起作用吗?它是否将类型强制转换为整数? (2认同)
  • 它不会圆,它会截断.什么是`-1.6 << 0`和`Math.round(-1.6)`? (2认同)
  • @voithos:`floor`向负无穷大移动,`ceil`向正无穷大,'round`轮,"cast"(或其等效的JavaScript)截断. (2认同)

Sal*_*n A 9

Math.random()返回0(包括)和1(不包括)之间的数字.将此数字乘以整数会产生一个具有小数部分的数字.该<<操作员是用于消除小数部分的快捷方式:

所有位运算符的操作数都以big-endian顺序和二进制补码格式转换为带符号的32位整数.

上述语句意味着JavaScript引擎将隐式地将运算<<符的两个操作数转换为32位整数; 对于数字,它通过切掉小数部分来实现(不适合32位整数范围的数字不仅仅是小数部分).

它只是JavaScript的细微差别,还是也出现在其他语言中?

您会注意到松散类型语言中的类似行为.PHP例如:

var_dump(1234.56789 << 0);
// int(1234)
Run Code Online (Sandbox Code Playgroud)

对于强类型语言,程序通常会拒绝编译.C#这样抱怨:

Console.Write(1234.56789 << 0);
// error CS0019: Operator '<<' cannot be applied to operands of type 'double' and 'int'
Run Code Online (Sandbox Code Playgroud)

对于这些语言,您已经有了类型转换运算符:

Console.Write((int)1234.56789);
// 1234
Run Code Online (Sandbox Code Playgroud)


Jon*_*eet 6

来自Mozilla的按位运算符文档(包括移位运算符)

所有位运算符的操作数都以big-endian顺序和二进制补码格式转换为带符号的32位整数.

所以基本上代码使用移位运算符的某种偶然方面作为由于移位0位而做的唯一重要的事情.伊克.

它只是JavaScript的细微差别,还是也出现在其他语言中?

我当然不能说所有语言,但Java和C#都不允许double值为左操作数和移位运算符.