JavaScript 中二进制字符串的负数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16155592/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 03:29:35  来源:igfitidea点击:

Negative numbers to binary string in JavaScript

javascriptnumberstostring

提问by fernandosavio

Anyone knows why javascript Number.toStringfunction does not represents negative numbers correctly?

有人知道为什么 javascriptNumber.toString函数不能正确表示负数吗?

//If you try
(-3).toString(2); //shows "-11"
// but if you fake a bit shift operation it works as expected
(-3 >>> 0).toString(2); // print "11111111111111111111111111111101"

I am really curious why it doesn't work properly or what is the reason it works this way? I've searched it but didn't find anything that helps.

我真的很好奇为什么它不能正常工作或者它以这种方式工作的原因是什么?我已经搜索过它,但没有找到任何有帮助的东西。

采纳答案by Daan

Short answer:

简答:

  1. The toString()function takes the decimal, converts it to binary and adds a "-" sign.

  2. A zero fill right shift converts it's operands to signed 32-bit integers in two complements format.

  1. toString()函数采用十进制,将其转换为二进制并添加“-”符号。

  2. 零填充右移将其操作数转换为两个补码格式的有符号 32 位整数。

A more detailed answer:

更详细的回答:

Question 1:

问题 1:

//If you try
(-3).toString(2); //show "-11"

It's in the function .toString(). When you output a number via .toString():

它在函数中.toString()。当您通过.toString()以下方式输出数字时:

Syntax

numObj.toString([radix])

If the numObj is negative, the sign is preserved.This is the case even if the radix is 2; the string returned is the positive binary representation of the numObj preceded by a - sign, not the two's complement of the numObj.

句法

numObj.toString([基数])

如果 numObj 为负,则保留符号。即使基数为 2,情况也是如此;返回的字符串是以 - 符号开头的 numObj 的正二进制表示,而不是 numObj 的二进制补码。

It takes the decimal, converts it to binary and adds a "-" sign.

它采用十进制,将其转换为二进制并添加一个“-”符号。

  1. Base 10 "3" converted to base 2 is "11"
  2. Add a sign gives us "-11"
  1. 基数 10 "3" 转换为基数 2 是 "11"
  2. 添加一个符号给我们“-11”

Question 2:

问题2:

// but if you fake a bit shift operation it works as expected
        (-3 >>> 0).toString(2); // print "11111111111111111111111111111101"

A zero fill right shift converts it's operands to signed 32-bit integers. The result of that operation is always an unsigned 32-bit integer.

零填充右移将其操作数转换为有符号的 32 位整数。该操作的结果始终是一个无符号的 32 位整数。

The operands of all bitwise operators are converted to signed 32-bit integers in two's complement format.

所有按位运算符的操作数都转换为二进制补码格式的有符号 32 位整数。

回答by Steve Wang

-3 >>> 0 (right logical shift) coerces its arguments to unsigned integers, which is why you get the 32-bit two's complement representation of -3.

-3 >>> 0(逻辑右移)将其参数强制为无符号整数,这就是为什么您会得到 -3 的 32 位二进制补码表示。

http://en.wikipedia.org/wiki/Two%27s_complement

http://en.wikipedia.org/wiki/Two%27s_complement

http://en.wikipedia.org/wiki/Logical_shift

http://en.wikipedia.org/wiki/Logical_shift

回答by Xotic750

var binary = (-3 >>> 0).toString(2); // coerced to uint32

console.log(binary);

console.log(parseInt(binary, 2) >> 0); // to int32

on jsfiddle

jsfiddle 上

output is

输出是

11111111111111111111111111111101
-3 

回答by trincot

.toString()is designed to return the sign of the number in the string representation. See EcmaScript 2015, section 7.1.12.1:

.toString()旨在返回字符串表示中数字的符号。参见EcmaScript 2015,第 7.1.12.1 节

  1. If mis less than zero, return the String concatenation of the String "-" and ToString(?m).
  1. 如果m小于零,则返回字符串 "-" 和 ToString(? m)的字符串连接。

This rule is no different for when a radix is passed as argument, as can be concluded from section 20.1.3.6:

当基数作为参数传递时,此规则没有什么不同,可以从第 20.1.3.6 节得出结论:

  1. Return the String representation of this Number value using the radix specified by radixNumber. [...] the algorithm should be a generalization of that specified in 7.1.12.1.
  1. 使用radixNumber指定的基数返回此 Number 值的字符串表示形式。[...] 该算法应该是 7.1.12.1 中指定的算法的概括。

Once that is understood, the surprising thing is more as to why it does not do the same with -3 >>> 0.

一旦理解了这一点,更令人惊讶的是为什么它对-3 >>> 0.

But thatbehaviour has actually nothing to do with .toString(2), as the value is already different before calling it:

这种行为实际上与 无关.toString(2),因为在调用它之前值已经不同了:

console.log (-3 >>> 0); // 4294967293

It is the consequence of how the >>>operator behaves.

这是>>>操作员行为的结果。

It does not help either that (at the time of writing) the information on mdnis not entirely correct. It says:

(在撰写本文时) mdn上的信息不完全正确也无济于事。它说:

The operands of all bitwise operators are converted to signed 32-bit integers in two's complement format.

所有按位运算符的操作数都转换为二进制补码格式的有符号 32 位整数。

But this is not true for allbitwise operators. The >>>operator is an exception to the rule. This is clear from the evaluation process specified in EcmaScript 2015, section 12.5.8.1:

但并非所有按位运算符都是如此。该>>>运营商是一个例外。从EcmaScript 2015 第 12.5.8.1 节中指定的评估过程可以清楚地看出这一点:

  1. Let lnumbe ToUint32(lval).
  1. lnum为 ToUint32( lval)。

The ToUint32operation has a step where the operand is mapped into the unsigned 32 bit range:

ToUint32操作具有,其中操作数被映射到32位无符号范围内的步骤:

  1. Let int32bitbe intmodulo 232.
  1. int32bitintmodulo 2 32

When you apply the above mentioned modulo operation (not to be confusedwith JavaScript's %operator) to the example value of -3, you get indeed 4294967293.

当您将上述模运算(不要与 JavaScript 的%运算符混淆)应用于示例值 -3 时,您确实会得到 4294967293。

As -3 and 4294967293 are evidently not the same number, it is no surprise that (-3).toString(2)is not the same as (4294967293).toString(2).

由于 -3 和 4294967293 显然不是同一个数字,因此(-3).toString(2)(4294967293).toString(2).

回答by evianpring

Just to summarize a few points here, if the other answers are a little confusing:

在这里总结几点,如果其他答案有点混乱:

  • what we want to obtain is the string representation of a negative number in binary representation; this means the string should show a signed binary number (using 2's complement)
  • the expression (-3 >>> 0).toString(2), let's call it A, does the job; but we want to know why and how it works
  • had we used var num = -3; num.toString(-3)we would have gotten -11, which is simply the unsigned binary representation of the number 3 with a negative sign in front, which is not what we want
  • expression A works like this:
  • 我们想要得到的是一个负数的二进制表示的字符串表示;这意味着字符串应该显示一个有符号的二进制数(使用 2 的补码)
  • 表达式(-3 >>> 0).toString(2),我们称之为 A,完成工作;但我们想知道为什么以及它是如何工作的
  • 如果我们使用var num = -3; num.toString(-3)我们会得到-11,它只是数字 3 的无符号二进制表示,前面有一个负号,这不是我们想要的
  • 表达式 A 的工作方式如下:

1) (-3 >>> 0)

1) (-3 >>> 0)

The >>>operation takes the left operand (-3), which is a signed integer, and simply shifts the bits 0 positions to the left (so the bits are unchanged), and the unsigned number corresponding to these unchanged bits.

>>>操作取左操作数(-3),它​​是一个有符号整数,并简单地将位 0 ​​位置向左移动(因此位不变),以及与这些未改变位对应的无符号数。

The bit sequence of the signed number -3 is the same bit sequence as the unsigned number 4294967293, which is what node gives us if we simply type -3 >>> 0into the REPL.

有符号数 -3 的位序列与无符号数 4294967293 的位序列相同,如果我们简单地输入-3 >>> 0REPL ,这就是节点给我们的。

2) (-3 >>> 0).toString

2) (-3 >>> 0).toString

Now, if we call toStringon this unsigned number, we will just get the string representation of the bits of the number, which is the same sequence of bits as -3.

现在,如果我们调用toString这个无符号数,我们将只得到该数位的字符串表示,它与 -3 的位序列相同。

What we effectively did was say "hey toString, you have normal behavior when I tell you to print out the bits of an unsigned integer, so since I want to print out a signed integer, I'll just convert it to an unsigned integer, and you print the bits out for me."

我们有效地做的是说“嘿,toString,当我告诉你打印出一个无符号整数的位时,你有正常的行为,所以因为我想打印出一个有符号整数,我会把它转换成一个无符号整数,然后你把这些部分打印出来给我。”