2

我想规范化一个数组,使每个值都在 [0-1) 中。即最大值永远不会是 1,但最小值可以是 0。这与返回相同范围内的数字的随机函数没有什么不同。

看着这个,我发现 .99999999999999999===1 是真的!同上 (1-Number.MIN_VALUE) === 1 但是 Math.ceil(Number.MIN_VALUE) 应该是 1。其他一些: Math.floor(.999999999999) 为 0 而 Math.floor(.99999999999999999) 为 1

好的,所以 JS 中存在舍入问题。

有什么方法可以将一组数字归一化,使其位于 [0,1) 范围内?

4

3 回答 3

3

检查 JavaScript 对每个表达式执行的步骤可能会有所帮助。

.99999999999999999===1

  1. 源文本.99999999999999999被转换为数字。最接近的数字是 1,这就是结果。(下一个最接近的数字是 0.99999999999999988897769753748434595763683319091796875,即1–2–53。)
  2. 然后将 1 与 1 进行比较。结果为真。

(1-Number.MIN_VALUE) === 1

  1. Number.MIN_VALUE为 2 –1074,约 5e–304。
  2. 1–2 –1074非常接近 1。确切的值不能表示为数字,因此使用最接近的值。同样,最接近的值为 1。
  3. 然后将 1 与 1 进行比较。结果为真。

Math.ceil(Number.MIN_VALUE)

  1. Number.MIN_VALUE为 2 –1074,约 5e–304。
  2. 该值的上限函数为 1。

Math.floor(.999999999999)

  1. 源文本.999999999999被转换为数字。最接近的数字是 0.99999999999900002212172012150404043495655059814453125,这就是结果。
  2. 该值的底函数为 0。

Math.floor(.99999999999999999)

  1. 源文本.99999999999999999被转换为数字。最接近的数字是 1,这就是结果。
  2. 1 的底函数为 1。

这里最多只有两件事令人惊讶。一是将源文本中的数字转换为内部数字值。但这应该不足为奇。当然,文本必须转换为数字的内部表示,而 Number 类型不能完美地存储所有无限多的数字。所以它必须圆。当然,数字非常接近 1 比 1。

另一个可能令人惊讶的事情是1-Number.MIN_VALUE1。但这实际上是同一个问题:确切的结果不可表示,但它非常接近 1,因此使用 1。

Math.floor功能正常工作。它从不引入任何错误,并且您不必做任何事情来保证它会向下舍入。它总是这样。

但是,由于您想对数字进行规范化,因此您似乎可能会在某个时候对数字进行除法。除法时,可能会出现舍入问题,因为很多除法的结果不能完全表示,所以必须进行舍入。

但是,这是一个单独的问题,您在此问题中没有提供足够的信息来解决您计划进行的具体计算。您应该为此打开一个单独的问题。

于 2013-06-01T00:47:37.947 回答
0

请理解一件事:这...

.999999999999999999

...只是一个数字文字。就像

.999999999999999998
.999999999999999997
.999999999999999996
...

......你看到了模式。

JavaScript 如何处理这些文字完全是另一回事。是的,这种处理受到可用于存储 Number的位数的限制。

根据定义,可能的浮点文字的数量是无限的——无论为它们设置的范围有多小。例如,以上图为例:你们中有多少人numbers very close to 1可以表达?是的,它是无限的:只需继续附加9到该行。

但是每个Number值的容器是非常有限的:它有 64 位。这意味着,它可以存储 2^64 个不同的值(Infinite-Infinite其中NaN) - 仅此而已。

无论如何,你想使用这样的文字吗?使用字符串来存储它们,而不是数字 - 以及一些 BigMath JS 库(随你选择)来处理这些值 - 再次作为字符串。

但是从您的问题来看,您似乎不是,因为您谈到了Numbers- Number values数组,也就是说。并且绝不可能在那里.999999999999999999存储,因为 JavaScript 中没有这样的 Number

于 2013-05-31T22:35:41.473 回答
0

Javascript 会将 0.999999999999999994 和 1 之间的任何数字视为 1,因此只需减去 0.000000000000000006。

当然,这并不像听起来那么容易,因为 .000000000000000006 在 Javascript 中被评估为 0,所以您可以执行以下操作:

function trueFloor(x)
{
    x = x * 100;
    if(x > .0000000000000006)
        x = x - .0000000000000006;
    x = Math.floor(x/100);
    return x;
}

编辑:或者至少你认为你可以。显然 JS 在将 .99999999999999999 传递给函数之前将其强制转换为 1,因此您必须尝试以下操作:

trueFloor("0.99999999999999999")

function trueFloor(str)
{
    x=str.substring(0,9) + 0;
    return Math.floor(x); //=> 0
}

不知道为什么你需要那种精确度,但理论上,我想它是有效的。你可以在这里看到一个工作小提琴

只要您将您的疯狂精确投射floatstring,那可能是您最好的选择。

于 2013-05-31T22:36:30.777 回答