`
ArcTan
  • 浏览: 3870 次
  • 性别: Icon_minigender_1
  • 来自: 北京
最近访客 更多访客>>
社区版块
存档分类
最新评论

JavaScript中的两个“0”(翻译)

阅读更多
本文翻译自JavaScript’s two zeros

JavaScript has two zeros: −0 and +0. This post explains why that is and where it matters in practice.
JavaScript 中有两个“0”: -0 和 +0 。这篇文章解释了为什么,并且指出实际生产中会造成什么影响

1.The signed zero
1.“-0”


Numbers always need to be encoded to be stored digitally. Why do some encodings have two zeros? As an example, let’s look at encoding integers as 4-digit binary numbers, via the sign-and-magnitude method. There, one uses one bit for the sign (0 if positive, 1 if negative) and the remaining bits for the magnitude (absolute value). Therefore, −2 and +2 are encoded as follows.
Binary 1010 is decimal −2
Binary 0010 is decimal +2
Naturally, that means that there will be two zeros: 1000 (−0) and 0000 (+0).
为了储存数字,需要将其编码为二级制,但为什么会编码出两个“0”呢,举个例子,将整数编码为4位二进制,由于整数有正有负,通过符号数值表示法,用第一位来表示符号(0 表示正数,1 表示负数),剩下的位表示数值(数的绝对值)。
所以,-2 和 +2 被编码为下面的形式:
二进制 1010 代表 -2
二进制 0010 代表 +2
很自然的,对于“2”也将出现两个:1000(-0) 和 0000(+0)


In JavaScript, all numbers are floating point numbers, encoded in double precision according to the IEEE 754 standard for floating point arithmetic. That standard handles the sign in a manner similar to sign-and-magnitude encoding for integers and therefore also has a signed zero. Whenever you represent a number digitally, it can become so small that it is indistinguishable from 0, because the encoding is not precise enough to represent the difference. Then a signed zero allows you to record “from which direction” you approached zero, what sign the number had before it was considered zero. Wikipedia nicely sums up the pros and cons of signed zeros:
在JavaScript中,所有的数字都被存储为浮点型数字,根据 IEEE 754 标准的浮点数算法编码为双精度浮点数。该标准类似于用符号数值表示法来编码整数,所以也会出现“-0”。当你要表示一个数字时,他可以表示一个小到与“0”区别不出来的数,因为编码方式无法足够精确的表示这种区别。用“-0”便可以记录一个数字在被认为是“0”之前,是“从坐标轴的那个方向”趋近真正的“0”的。关于“-0”的优劣,维基百科做了很好的总结。
引用
It is claimed that the inclusion of signed zero in IEEE 754 makes it much easier to achieve numerical accuracy in some critical problems, in particular when computing with complex elementary functions. On the other hand, the concept of signed zero runs contrary to the general assumption made in most mathematical fields (and in most mathematics courses) that negative zero is the same thing as zero. Representations that allow negative zero can be a source of errors in programs, as software developers do not realize (or may forget) that, while the two zero representations behave as equal under numeric comparisons, they are different bit patterns and yield different results in some operations.

引用
在 IEEE 754 标准中使用“-0”,更容易解决复杂数学计算中的精度等关键问题。另一方面,“-0”的概念与大多数数学领域(和数学课程)中的数学假设背道而驰,因为“-0”和“+0”是相同的。允许“-0”的存在,开发人员可能会没有认识到(或忘了)这一点,由于两个“0”的二进制表示不同,“-0”的存在,在某些计算中会产生不同的结果,导致判断两个数字相等的代码可能隐含一些错误。
此段维基百科引用的英文没有对应的中文版,所以自己做了翻译。

JavaScript goes to some lengths to hide the fact that there are two zeros.
JavaScript 做了很多工作来隐藏有两个“0”的事实。

2.Hiding the zero’s sign
2.隐藏“0”的符号

In JavaScript, you’ll usually write 0, which always means +0. But it also displays −0 simply as 0. The following is what you see when you use any browser command line or the Node.js REPL:
通常认为,JavaScript 中显示的“0”,表示的都是“+0”。其实“-0”也直接显示为“0”,下面的例子显示了浏览器命令行和Node.js中的执行情况:
    > -0
    0

The reason is that the standard toString() method converts both zeros to the same "0".
原因是按照规则两个“0”都通过调用 toString() 方法转换成了相同的结果“0”:
    > (-0).toString()
    '0'
    > (+0).toString()
    '0'

The illusion of a single zero is also perpetrated by the equals operators. Even strict equality considers both zeros the same, making it very hard to tell them apart (in the rare case that you want to).
等于“==”操作符同样这样对待“-0”,甚至全等符号“===”也判断为他们相等,这使他们很难被区别(但在某些情况下需要区分)。
    > +0 === -0
    true

The same holds for the less-than and greater-than operators – they consider both zeros equal.
大于“>”小于“<”符号同样判断两个“0”相等。
    > -0 < +0
    false
    > +0 < -0
    false


3.Where the zero’s sign matters
3.“0”的符号都影响了哪些地方

The sign of the 0 rarely influences results of computations. And +0 is the most common 0. Only a few operations produce −0, most of them just pass an existing −0 through. This section shows a few examples where the sign matters. For each example, think about whether it could be used to tell −0 and +0 apart, a task that we will tackle in Sect. 4. In order to make the sign of a zero visible, we use the following function.
“-0”在一些很罕见的地方影响计算结果。通常“+0”就是通常的“0”。只有少数运算产生“-0”的结果,大多数都直接忽略“-0”的存在。这一段将展示“-0”在哪些情况下产生影响。想一想下面每一个例子要区别“-0”和“+0”的原因,在展示过程中,为了能清晰的看到“-0”,我们将使用下面这个函数。
    function signed(x) {
        if (x === 0) {
            // isNegativeZero() will be shown later 【isNegativeZero() 将在后文中给出实现】
            return isNegativeZero(x) ? "-0" : "+0";
        } else {
            // Otherwise, fall back to the default 【其它情况下,使用默认方法】
            // We don’t use x.toString() so that x can be null or undefined 【null 或 undefined 不能使用 x.toString() 的写法】
            return Number.prototype.toString.call(x);
        }
    }


3.1.Adding zeros
3.1.加法

Quoting Sect. 11.6.3 of the ECMAScript 5.1 specification, “Applying the Additive Operators to Numbers”:
引用
The sum of two negative zeros is −0. The sum of two positive zeros, or of two zeros of opposite sign, is +0.

For example:

引用 ECMAScript 5.1 规范第 11.6.3 节 “加法的变形” 的说明
引用
两个“-0”相加得“-0”。两个“+0”相加得“+0”,符号相反的两个“0”相加得“+0”

如下:

    > signed(-0 + -0)
    '-0'
    > signed(-0 + +0)
    '+0'

This doesn’t give you a way to distinguish the two zeros, because what comes out is as difficult to distinguish as what goes in.
这并不能告诉你怎样区别两个“0”,因为运算的输入和输出一样难区别。

3.2.Multiplying by zero
3.2.乘法

When multiplying with zero with a finite number, the usual sign rules apply:
当两个非无穷数与“0”相乘时,就可以用通常的乘法规则了。
    > signed(+0 * -5)
    '-0'
    > signed(-0 * -5)
    '+0'

Multiplying an infinity with a zero results in NaN:
无穷数与“0”相乘,结果为非数字(NaN)
    > -Infinity * +0
    NaN


3.3.Dividing by zero
3.3.除法

You can divide any non-zero number (including infinities) by zero. The result is an infinity whose sign is subject to the usual rules.
用任何非零数(包括无穷)来除以“0”。结果符合通常的符号规则。
    > 5 / +0
    Infinity
    > 5 / -0
    -Infinity
    > -Infinity / +0
    -Infinity

Note that -Infinity and +Infinity can be distinguished via ===.
注意,正无穷和负无穷可以用“===”进行区别。
    > -Infinity === Infinity
    false

Dividing a zero by a zero results in NaN:“0”除以“0”为非数字(NaN)。
    > 0 / 0
    NaN
    > +0 / -0
    NaN


3.4.Math.pow()
3.4.乘方运算

The following is a table of the results of Math.pow() if the first argument is zero:
下表列出了以“0”为底数的乘法运算结果
pow(+0, y<0) → +∞ 
pow(−0, odd y<0) → −∞ //【奇数次幂】
pow(−0, even y<0) → +∞ //【偶数次幂】

Interaction:
    > Math.pow(+0, -1)
    Infinity
    > Math.pow(-0, -1)
    -Infinity


3.5.Math.atan2()
3.5.极坐标弧度

The following is a table of the results that are returned if one of the arguments is zero.
下表列出了目标点横纵坐标为零时的返回值
atan2(+0, +0) → +0 
atan2(+0, −0) → +π 
atan2(−0, +0) → −0 
atan2(−0, −0) → −π 

atan2(+0, x<0) → +π 
atan2(−0, x<0) → −π 

Hence, there are several ways to determine the sign of a zero. For example:
因此,我们发现了区分两个零的方法,如:
    > Math.atan2(-0, -1)
    -3.141592653589793
    > Math.atan2(+0, -1)
    3.141592653589793

atan2 is one of the few operations that produces −0 for non-zero arguments:
atan2 是少数几个能用非零参数产生“-0”的运算之一
atan2(y>0, +∞) → +0 
atan2(y<0, +∞) → −0

Therefore:因此
    > signed(Math.atan2(-1, Infinity))
    '-0'


3.6.Math.round()
3.6.四舍五入

Math.round() is another operation that returns −0 for arguments other than −0 and +0:
Math.round()是另一个不用“-0”和“0”能产生“-0”的运算。
    > signed(Math.round(-0.1))
    '-0'

Here we have the effect that we talked about at the beginning: The sign of the zero records the sign of the value before rounding, “from which side” we approached 0.
现在我们可以体会前文中【用“-0”便可以记录一个数字在被认为是“0”之前,是“从坐标轴的那个方向”趋近真正的“0”的。】的含义了。

4.Telling the two zeros apart
4.区分两个“0”

The canonical solution for determining the sign of a zero is to divide one by it and then check whether the result is -Infinity or +Infinity:
一个典型的辨别“0”的符号的方法,就是检查用“1”除以它的运算结果是正无穷还是负无穷:
    function isNegativeZero(x) {
        return x === 0 && (1/x < 0);
    }

The above sections showed several other options. One original solution comes from Allen Wirfs-Brock. Here is a slightly modified version of it:
前文也展示了另外一些选择。Allen Wirfs-Brock 还提供了一种基于对象原型的方法,这里有一个稍作修改的版本。
function isNegativeZero(x) {
    if (x !== 0) return false;
    var obj = {};
    Object.defineProperty(obj, 'z', { value: -0, configurable: false });
    try {
        // Is x different from z’s previous value? Then throw exception.【如果 x 与前面定义的 z 取值不同,则会抛出异常。】
        Object.defineProperty(obj, 'z', { value: x });
    } catch (e) {
        return false
    };
    return true;
}

Explanation: In general, you cannot redefine a non-configurable property – an exception will be thrown. For example:
说明:通常,你不能重定义一个“不可配置”(non-configurable)的属性,如果这么做会抛出下面这个异常:
    TypeError: Cannot redefine property: z

However, JavaScript will ignore your attempt if you use the same value as the existing one. In this case, whether a value is the same is not determined via ===, but via an internal operation that distinguishes −0 and +0. You can read up on the details in Wirfs-Brock’s blog post (freezing an object makes all properties non-configurable).
JavaScript 试图会忽略你对用相同的值进行的修改。在这个例子中,值相同并不是通过全等运算符“===”来判断的,是通过一种内在的机制来区分“-0”和“+0”的。详细内容可以去读 Wirfs-Brock 的博文“设置所有属性为不可配置实现对象锁定(freezing an object makes all properties non-configurable)

5.Conclusion
5.结论

We have seen that there are two zeros, because of how the sign is encoded for JavaScript’s numbers. However, −0 is normally hidden and it’s best to pretend that there is only one zero. Especially, because the difference between the zeros has little bearing on computations. Even strict equality === can’t tell them apart. Should you, against all expectations or just for fun, need to determine the sign of a zero, there are several ways to do so. Note that the slightly quirky existence of two zeros is not JavaScript’s fault, it simply follows the IEEE 754 standard for floating point numbers.
我们已经看到两个零的符号在 JavaScript中是怎样编码的。虽然通常情况下“-0”被隐藏的很好,伪装成就像只有一个“0”存在的样子。特别是一些运算掩盖了这点小小的不同。使全等“===”操作也无法区别他们。如果你想要区分两个“0”,不管是有意为之,还是只为了好玩儿,这里已经提供了一些方法。要注意,有两个“0”这一点儿古怪之处,并不是 JavaScript 的bug,而是遵从了 IEEE 754 规范的浮点数规则。

6.Related reading
6.扩展阅读

This post is part of a series on JavaScript numbers that comprises the following posts:
  • Integers and shift operators in JavaScript
  • Displaying numbers in JavaScript
Furthermore, the blog post “Stricter equality in JavaScript” examines that === cannot detect either the value NaN or the sign of a zero.
本文是几篇讨论 JavaScript 中数字的系列文章中的一篇,系列的其他文章在下面:
另外,JavaScript中的严格比较研究了“===”不能用于检查 NaN 或 “-0” 的各种情况。
分享到:
评论

相关推荐

    geogebra javascript API参考潘立强翻译部分(1)1

    在这个示例中,我们将创建两个按钮,一个用于隐藏对象 "A",另一个用于显示对象 "A"。我们使用了 GGBApplet 对象的 setVisible() 方法来实现这个功能。 ('A', false);"&gt; ('A', true);"&gt; 示例 3:调用 GeoGebra...

    javascript经典特效---数字翻译成英语.rar

    1. **字符串操作**:JavaScript提供了多种字符串方法,如`toString()`用于将数字转换为字符串,`charAt()`获取指定位置的字符,以及`concat()`连接两个或更多字符串。 2. **范围划分**:通常,我们会根据数字的大小...

    JavaScript语言精粹(翻译版+英文版)

    这两个版本的结合,为读者提供了灵活的学习方式,既可以离线阅读,也可以在线探索。 总的来说,《JavaScript语言精粹》是学习JavaScript不可或缺的参考资料。无论你是刚接触编程的新手,还是希望巩固和深化...

    JDK_1.8中文谷歌和百度翻译两个版本

    Java Development Kit(JDK)是Java编程语言的核心组件,它包含了一套开发和运行Java应用程序所需的工具和库。...无论你是初学者还是经验丰富的开发者,这两个版本的翻译都将是你学习和工作中不可或缺的参考资料。

    JavaScript+jQuery中文帮助文档

    描述中的“js和jq两个帮助文档”意味着这个压缩包包含了两部分内容:一份是关于JavaScript的,另一份是关于jQuery的。"现在把自己收集的信息和大家一起分享"这部分,说明这些文档可能是作者整理和翻译的,目的是为了...

    javascript DOM高级程序设计 及 javascript 设计模式

    《JavaScript DOM高级程序设计》 首先教你搭建一个类似JQuery的额工具函数库,然后通过讲解几个实际中经常遇到的几个应用例子,会让初学者受益匪浅 《JavaScript设计模式》主要讲Javascript的设计模式,说实话,翻译...

    JavaScript_将营销语言翻译成人类可读的文本的书签.zip

    在提供的压缩包中,有两个文件:`说明.txt`和`bullshit.js_main.zip`。`说明.txt`很可能包含了关于这个项目或者代码的详细解释,比如实现的算法、使用的技术和步骤等。而`bullshit.js_main.zip`则可能是项目的主代码...

    google翻译接口(js的api实现与C#两个版本)

    Google翻译接口是其中一种广泛使用的解决方案,它提供了JavaScript和C#两种编程语言的实现方式。本文将深入探讨Google翻译接口的原理、使用方法以及在JavaScript和C#中的具体实现。 Google翻译接口是Google ...

    How to do everything with javascript

    此外,JavaScript还提供了事件冒泡和事件捕获两种事件传播机制。 最后,AJAX(异步JavaScript和XML)是创建动态、无刷新页面的关键技术。通过XMLHttpRequest对象,开发者可以向服务器发送异步请求,获取数据后更新...

    有道和百度翻译demo

    本文将深入探讨“有道和百度翻译demo”这个主题,它涉及到使用HTML和JavaScript调用两个著名在线翻译平台——有道翻译和百度翻译的API。 首先,有道翻译API是一个强大的工具,允许开发者集成到自己的网页或应用中,...

    JavaScript资源大全中文版

    在测试框架方面,Jest和Mocha是两个广泛使用的工具。Jest以其全面的功能集(包括模拟、快照测试和并行测试)和易于上手而著称,而Mocha则以其灵活的异步支持和丰富的生态系统备受青睐。 运行器如Babel用于将ES6+的...

    基于JavaScript的无需配置全自动HTML页面翻译源码

    该项目是一款基于JavaScript的HTML页面全自动翻译解决方案,无需任何配置,仅需两行JavaScript代码即可实现。该项目包含137个文件,涵盖91个JavaScript文件、14个Java文件、9个Markdown文件、5个HTML文件、4个GIF...

    javascript编程语言教程

    通过对JX与Linux在两个非平凡的操作系统组件(文件系统和NFS服务器)上的性能进行对比,可以看出JX在单体配置下,在文件系统基准测试中的性能达到了Linux的大约40%到100%,而在NFS基准测试中的性能约为Linux的80%。...

    Javascript中的陷阱大集合【译】

    在JavaScript中,双等号`==`操作符在比较两个值时会进行类型转换,这意味着即使两边的数据类型不同,也会尝试将它们转换为相同类型再进行比较。例如: ```javascript "1" == 1 // true ``` 在这个例子中,字符串`...

    JavaScript_秘密花园

    这是由于JavaScript解析器的一个缺陷,它尝试将点号解析为浮点数的一部分,从而导致语法错误: ```javascript 2.toString(); // SyntaxError ``` - **绕过数字字面量的限制**:有一些技巧可以让数字字面量看起来...

    基于microsoftTranslator实现js中英文转换

    现在,我们可以创建一个简单的用户界面,包含两个按钮,分别用于从中文翻译为英文和从英文翻译为中文。当用户点击按钮时,触发对应的翻译操作: ```html &lt;!DOCTYPE html&gt; 中英文转换 请输入文本"&gt; 翻译为...

    JavaScript_Garden_CN

    5. **核心概念**: 强调了避免使用`eval`的重要性,解释了`undefined`和`null`的区别,以及自动分号插入机制,这些都是JavaScript编程中容易忽视但至关重要的细节。 6. **其他**: 提及了`setTimeout`和`setInterval`...

    编写可维护面向对象的JavaScript代码[翻译]

    在JavaScript中,创建类和对象有两种基本方式: 1. 使用构造函数和原型(Prototypes): ```javascript function Employee(name, title, salary) { this.name = name; this.title = title; this.salary = salary...

    JavaScript常用语句50条

    通过这两个事件处理器,可以防止用户对页面内容执行复制和剪切操作。这与`onselectstart`结合使用时,能更全面地保护页面内容不被复制。 ### 5. 自定义浏览器图标:`&lt;link rel="Shortcut Icon" href="favicon.ico"&gt;...

Global site tag (gtag.js) - Google Analytics