当前位置:  开发笔记 > 编程语言 > 正文

2.9999999999999999 >> .5?

如何解决《2.9999999999999999>>.5?》经验,为你挑选了5个好方法。

我听说你可以将数字右移一个.5而不是使用Math.floor().我决定检查其限制以确保它是合适的替代品,因此我检查了以下值并在Google Chrome中获得了以下结果:

2.5 >> .5 == 2;
2.9999 >> .5 == 2;
2.999999999999999 >> .5 == 2;  // 15 9s
2.9999999999999999 >> .5 == 3;  // 16 9s

在一些摆弄之后,我发现两个最高可能的值,当右移0.5时,将产生2,在Chrome和Firefox中是2.999999999999997779553950949686919152736663818359374999999(以及9重复).IE中的数字为2.9999999999999997779.

我的问题是:数字的意义是什么.0000000000000007779553950749686919152736663818359374?这是一个非常奇怪的数字,它真的激起了我的好奇心.

我一直试图找到答案或至少某种模式,但我认为我的问题在于我真的不理解按位操作.我原则上理解这个想法,但是将一个序列移动到.5对我来说根本没有任何意义.任何帮助表示赞赏.

为了记录,奇怪的数字序列以2 ^ x变化.以下数字的最高可能值仍然正确截断:

for 0: 0.9999999999999999444888487687421729788184165954589843749¯
for 1: 1.9999999999999999888977697537484345957636833190917968749¯
for 2-3: x+.99999999999999977795539507496869191527366638183593749¯
for 4-7: x+.9999999999999995559107901499373838305473327636718749¯
for 8-15: x+.999999999999999111821580299874767661094665527343749¯
...and so forth

Ates Goral.. 63

实际上,您只是在第一个操作数上执行floor(),而不进行任何浮点运算.由于左移和右移位操作仅对整数操作数有意义,因此JavaScript引擎首先将两个操作数转换为整数:

2.999999 >> 0.5

变为:

Math.floor(2.999999) >> Math.floor(0.5)

反过来又是:

2 >> 0

移位0位表示"不进行移位",因此您最终得到第一个操作数,只需截断为整数.

SpiderMonkey源代码具有:

switch (op) {
  case JSOP_LSH:
  case JSOP_RSH:
    if (!js_DoubleToECMAInt32(cx, d, &i)) // Same as Math.floor()
        return JS_FALSE;
    if (!js_DoubleToECMAInt32(cx, d2, &j)) // Same as Math.floor()
        return JS_FALSE;
    j &= 31;
    d = (op == JSOP_LSH) ? i << j : i >> j;
    break;

您看到某些数字的"四舍五入"是由于JavaScript引擎无法处理超过一定精度的十进制数字,因此您的数字最终会向上舍入到下一个整数.在浏览器中尝试此操作:

alert(2.999999999999999);

你会得到2.999999999999999.现在尝试再添加一个9:

alert(2.9999999999999999);

你会得到3分.



1> Ates Goral..:

实际上,您只是在第一个操作数上执行floor(),而不进行任何浮点运算.由于左移和右移位操作仅对整数操作数有意义,因此JavaScript引擎首先将两个操作数转换为整数:

2.999999 >> 0.5

变为:

Math.floor(2.999999) >> Math.floor(0.5)

反过来又是:

2 >> 0

移位0位表示"不进行移位",因此您最终得到第一个操作数,只需截断为整数.

SpiderMonkey源代码具有:

switch (op) {
  case JSOP_LSH:
  case JSOP_RSH:
    if (!js_DoubleToECMAInt32(cx, d, &i)) // Same as Math.floor()
        return JS_FALSE;
    if (!js_DoubleToECMAInt32(cx, d2, &j)) // Same as Math.floor()
        return JS_FALSE;
    j &= 31;
    d = (op == JSOP_LSH) ? i << j : i >> j;
    break;

您看到某些数字的"四舍五入"是由于JavaScript引擎无法处理超过一定精度的十进制数字,因此您的数字最终会向上舍入到下一个整数.在浏览器中尝试此操作:

alert(2.999999999999999);

你会得到2.999999999999999.现在尝试再添加一个9:

alert(2.9999999999999999);

你会得到3分.



2> John Milliki..:

这可能是我见过的最糟糕的想法.它唯一可能的目的是赢得一场晦涩的代码竞赛.你发布的长数没有意义 - 它们是底层浮点实现的工件,通过上帝过滤 - 知道有多少中间层.通过一小部分字节进行位移是疯狂的,我很惊讶它没有引发异常 - 但这是Javascript,总是愿意重新定义"疯狂".

如果我是你,我会避免使用这个"功能".它唯一的值是作为异常错误条件的可能根本原因.Math.floor()对下一个维护代码的程序员使用并怜悯.


确认我在阅读问题时遇到的一些怀疑:

右移任何小数x的任何小数y将简单地截断x,给出与Math.floor()完全混淆读者时相同的结果.

2.999999999999999777955395074968691915 ...只是可以与"3"区分开的最大数字.尝试自己评估它 - 如果你向它添加任何东西,它将评估为3.这是浏览器和本地系统的浮点实现的工件.


"这可能是我见过的最糟糕的想法." 我告诉你一个999.9999999999999999999999次停止夸大.
在所有当前的发货JS引擎`Math.floor`(即使你在本地缓存`floor`)比简单地做bitop要慢得多(想想数量级).最快的是`someNumber | 0`.也就是说这些技巧对于大于2 ^ 32的值是不安全的,并且大多数在3~31时变得不安全.

3> Eduardo..:

如果你想更深入,请阅读"每个计算机科学家应该知道的关于浮点算术的内容":http://docs.sun.com/source/806-3568/ncg_goldberg.html



4> Rob Walker..:

我不认为你的正确转变是相关的.您只是超出了双精度浮点常数的分辨率.

在Chrome中:

var x = 2.999999999999999777955395074968691915273666381835937499999;
var y = 2.9999999999999997779553950749686919152736663818359375;

document.write("x=" + x);
document.write(" y=" + y);

打印出:x = 2.9999999999999996 y = 3



5> Zach Snow..:

试试这个javascript:alert(parseFloat("2.9999999999999997779553950749686919152736663818359374999999"));

然后试试这个:alert(parseFloat("2.9999999999999997779553950749686919152736663818359375"));

你看到的是简单的浮点不准确.有关详细信息,请参阅此示例:http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems.

基本问题是浮点值可以表示第二个数字的最接近值大于或等于3,而浮点数可以达到第一个数字的关闭严格小于3.

至于为什么右移0.5会使任何事情变得明朗,似乎0.5本身就是事先将其转换为int(0).然后像往常一样通过截断将原始float(2.999 ...)转换为int.

推荐阅读
地之南_816
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有