代码之家  ›  专栏  ›  技术社区  ›  codekaizen

扩展(80位)双浮点在x87,而不是SSE2-我们没有错过它?

  •  31
  • codekaizen  · 技术社区  · 15 年前

    我今天读到关于 researchers discovering that NVidia's Phys-X libraries use x87 FP vs. SSE2

    英特尔在2000年底推出了P4,开始不鼓励使用x87。AMD从2003年的K8开始就不推荐使用x87,因为x86-64被定义为支持SSE2;自2005年以来,viasc7一直支持SSE2。在64位版本的Windows中,x87在用户模式下是不受欢迎的,在内核模式下是完全禁止的。自2005年以来,业界几乎所有人都推荐SSE而不是x87,除非软件必须运行在嵌入式奔腾或486上,否则没有理由使用x87。

    我想知道这件事。我知道x87在内部使用80位扩展双精度来计算值,而SSE2没有。这对任何人都不重要吗?我觉得很奇怪。我知道,当我在平面上对点、线和多边形进行计算时,在进行减法运算时,值可能会出人意料地出错,而且由于精度不够,区域可能会塌陷,线会彼此重叠。我想,使用80位值和64位值可能会有所帮助。

    这不正确吗?如果没有,如果x87被淘汰,我们可以用什么来执行扩展的双FP操作?

    4 回复  |  直到 15 年前
        1
  •  28
  •   codekaizen    15 年前

    x87的最大问题基本上是所有寄存器操作都是在80位中完成的,而大多数时候人们只使用64位浮点(即双精度浮点)。所发生的是,将64位浮点加载到x87堆栈中,然后将其转换为80位。在80位中对它执行一些操作,然后将其存储回内存,并将其转换为64位。与仅使用64位执行所有操作相比,您将得到不同的结果,并且使用优化编译器时,一个值可能经过的转换次数非常不可预测,因此在执行回归测试时很难验证您是否得到了“正确”的答案。

    另一个问题仅从编写程序集(或间接编写程序集,在为编译器编写代码生成器的情况下)的角度来看是重要的,即x87使用寄存器堆栈,而SSE使用可单独访问的寄存器。有了x87,你就有了一堆额外的指令来操作堆栈,我想Intel和AMD宁愿用SSE代码让他们的处理器运行得快,也不愿让那些额外的堆栈操作x87指令运行得快。

    顺便说一句,如果你有不准确的问题,你会想看看这篇文章 What every programmer should know about floating-point arithmetic

        2
  •  5
  •   phuclv    4 年前

    void print_dist_squared(double x1, double y1, double x2, double y2)
    {
      printf("%12.6f", (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
    }
    

    应该有一些类型可以用来捕获和替换公共子表达式 x2-x1 y2-y1

    void print_dist_squared(double x1, double y1, double x2, double y2)
    {
      some_type dx = x2-x1;
      some_type dy = y2-y1;
      printf("%12.6f", dx*dx + dy*dy);
    }
    

    不改变程序的语义。不幸的是,ansic未能指定任何可用于 some_type

    事实上,扩展精度类型在没有浮点单元的平台上的价值与在x87处理器上的价值一样,因为在这种处理器上,像x+y+z这样的计算需要以下步骤:

    1. 同样打开y包装。
    2. 如果x和y有不同的符号,左移尾数直到最左边的位是1,并适当调整指数。
    3. 打开临时结果的包装。
    4. 右移值的尾数和较低的指数(如果有的话),然后加上或减去这些值。
    5. 如果前面的结果和z有不同的符号,左移尾数直到最左边的位是1,并适当调整指数。
    6. 将指数和尾数重新打包为双精度格式。

    使用扩展精度类型可以消除步骤4、5和6。由于53位尾数太大,无法容纳少于四个16位寄存器或两个32位寄存器,因此使用64位尾数执行加法并不比使用53位尾数慢,因此使用扩展精度数学可以提供更快的计算速度,而且没有任何缺点 在一种支持适当类型以保存临时结果的语言中 . 没有理由责怪英特尔提供了一个FPU,可以执行浮点数学的方式,这是过去的 非FPU芯片上最有效的方法。

        3
  •  3
  •   Anonymous    9 年前

    始终使用80位中间算法,如果你可以摆脱它的速度明智。如果这意味着您必须使用x87数学,那么就这样做。对它的支持无处不在,只要人们继续做正确的事情,它就会无处不在。

        4
  •  0
  •   user6801759    9 年前

    双精度比f80小11位(大约2.5个字节/位数),对于许多应用程序(主要是游戏)来说,这不会有什么坏处。但你将需要所有可用的准确性,比如说,太空计划或医疗应用程序。

    当有人说f80(并被它劝阻)在堆栈上运行时,这有点误导。FPU的寄存器和操作类似于堆栈操作,也许这让人摸不着头脑。它实际上是基于内存的(加载/存储),而不是堆栈本身,例如,与调用cdecl stdcall这样的约定相比,cdecl stdcall实际上通过堆栈传递参数。没什么不对的。

    对于游戏和普通的简单应用程序(几乎所有),你只需使用两次就不会有人死亡。但对于一些严肃的数学或科学应用程序来说,你不能抛弃f80。