为什么浮点运算是对语言设计中平台无关性的挑战?

        现代语言为了达到编译一次、到处运行的目的,纷纷采用虚拟机的方式,将目标语言锁定为虚拟机支持的中间语言。这样不需要知道最终程序运行的软硬件系统,达到所谓的平台无关性,最典型的例子就是Java和C#了。平台无关性想法很好,但是实现起来却并不容易,充满了挑战。其中之一的挑战就是浮点数运算。

        浮点数一般是指float和double,其中float是32位,double是64位。我们先看下面这个简单的语句:

                double w = x * y / z;

        要想在所有的机器上运行这条语句,得到相同的w值是很困难的,这很CPU的设计很有关系。现在很多的Intel处理器,在进行浮点运算是,使用的是80位的寄存器,而不是64位的。这些CPU是这样处理上述这条语句的:

               步骤1.  计算x * y ,得到中间结果w0,将w0存入一个80位的寄存器;

               步骤2.  计算w0/z,得到中间结果w1,将w1存入一个80位的寄存器;

               步骤3.  将80位的w1裁剪成60位的w。

         很明显,相比全部使用64位寄存器的CPU,采用80位寄存器的Intel CPU更精确,因为w0更精确。同时,这也说明了这条语句在不同的CPU下运行,得到的结果可能不一样,这也就违背了平台无关性这条原则。

          当然,为了达到平台无关性,虚拟机可以在上述步骤1和步骤2之间,增加下面这条指令:

                步骤1.5  将80位的w0裁剪成60位的w0;

          这样做有两个缺点:

                 1. 计算效率降低了,因为多运行了一条指令;

                 2. 计算结果可能不正确,出现指数溢出的情况,因为x * y的结果有可能超过double的范围了。

          

           那么,虚拟机到底是否需要生成步骤1.5的指令呢?Java很聪明,它把这个决定权给了开发者。默认情况下,Java是不会生成步骤1.5的指令的。然而,Java提供了一个关键字strictfp,可以让Java生成这条多余的指令。例如,下面的函数multiply能保证,它里面的浮点运算在所有的平台上得到一致的结果。

                  public static strictfp double multiply(double x, double y)

           当然,其实我们不用太在意了strictfp关键字,因为用到它的时候很少,绝大多数情况下不用strictfp,只要知道有这回事情就可以了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值