日期:2014-05-16  浏览次数:20409 次

每一个JavaScript开发者应该了解的浮点知识

在JavaScript开发者的开发生涯中的某些点,总会遇到奇怪的BUG——看似基础的数学问题,但却又觉得有些不对劲。总有一天,你会被告知JavaScript中的数字实际上是浮点数。试图了解浮点数和为什么他们如此奇怪,迎接你的将是一片又臭又长的文章。本文的目的是给JavaScript开发者简单讲解浮点数。

本文假设读者熟悉的用二进制表示的十进制数字(即1被写成1b,2是10b,3是11b,4是100b……等)。为了使文章表达的更清楚,在本章中,“十进制”主要是指计算机内部的十进制数字表示法(例如:2.718)。“二进制”在本文中指计算机内部的表示。书面陈述将分别被称为“以十为底″和“以二为底″。

浮点数

什么是浮点数,我们开始认为我们见过各种数字,我可可以说1是一个整数,因为它没有分数部分。

?被称为分数。这意味着,将一平均分开为二,分数是浮点运算中一个非常重要的概念。

0.5通常被称为一个十进制数。然而,有一个很重要的区别必须阐明——0.5实际上是分数?的十进制(以十为底)表示。本文中,我们将这种表示方法称为点表示法。我们把0.5称为有限表示(有限小数)因为其分数表示的数字是有限的——5后面没有其他数字。表示?的0.3333…是无限表示的例子。这个想法在我们的讨论非常重要。 

还存在另一种表示全部整数,分数或小数的方法。你可能已经见过。它看起来像这样:6.022×1023(注:这是阿伏伽德罗数,这是摩尔的化学溶液中的分子的数目)。它通常被称为标准形式,或科学记数法。形式可以被抽象为像下面这样:

D1.D2D3D4...Dp x BE

这种通用形式被称作浮点数。

由p和D组成的序列——D1.D2D3D4...Dp——被称为有效数字或尾数。p是有效数字的权重,通常称为精度。有效数后的x是符号的一部分(本文中的乘法符号,将用*表示)。其后是基数,基数后是指数。该指数可以是正或负。

浮点数的好处是它可以用来表示任何数值。例如,整数1可以表示为1.0×100。光的速度可以表示为2.99792458×108 m/s。1/2可以被表示为二进制形式0.1×20。

移除小数点

在上面的例子中,我们仍然保留小数点(小数点在数字里面)。当用二进制表示数值的时候,这带来了一些问题。任意给定一个浮点数,比如π(PI),我们可以将其表示为一个浮点数:3.14159 x 100。用二进制表示,它看起来像这样:11.00100100 001111……假设在十六位机里表示数字,这意味着数字被放在机器里会是这样的:11001001000011111。现在的问题是:小数点应该放在哪里?这甚至不涉及指数(我们默认基数为2)。

如果数字变为5.14159?整数部分将变为101而不是11,增加了一位。当然,我们可以指定字段的前N位属于整数部分(即小数点的左边),其余属于小数部分,但那是另一篇关于定点数的话题。

一旦我们移除小数点后,我们只有两件东西需要记录:指数和尾数。我们可以通过应用变换公式将小数点移除,使广义浮点数看起来像这样:

D1D2D3D4...Dp / (Bp-1) x BE

这就是我们得到的大多数二进制浮点数。注意,现在有效数是一个整数。这使得它更易于存储一个浮点数在机器上。事实上,应用最广泛的二进制浮点数表示方法是IEEE 754标准。

IEEE 754

JavaScript中的浮点数采用IEEE-754格式的规定。更具体的说是一个双精度格式,这意味着每个浮点数占64位。虽然它不是二进制表示浮点数的唯一途径,但它是目前最广泛使用的格式。该格式用64位二进制表示像下面这样:

SIGNEXPONENTMANTISSA