可移植性是 Java 语言的设计目标之一, 无论在哪个虚拟机上运行, 同一运算都应得到同样的结果. 但对于浮点数的算术运算, 实现这样的可移植性相当困难. double 类型使用 64 位存出一个数值, 而有些处理器使用 80 位浮点寄存器, 这些寄存器增加了中间过程的计算精度. 比如以下计算:
double w = x * y / z;
很多 Intel 处理器计算 x * y, 并将结果存储在 80 为的寄存器中, 再除以 z 并将结果截断为 64 位, 这样可以得到一个更加精确的计算结果, 还能避免产生指数溢出. 但是这个结果可能与始终在 64 位机器上计算的结果不太一样.
最初的规范规定 Java 虚拟机所有中间计算都必须进行截断, 以保证无论是 80 位寄存器还是 64 位寄存器的浮点计算都能保持完全相同的计算结果, 但这样不仅可能导致溢出, 而且更消耗时间. 为此, Java 承认了最优性能与理想结果之间存在的冲突, 并给予了改进.
在默认情况下, Java 虚拟机允许对中间计算结果采用扩展的精度(如果处理器支持), 但是对于使用 stricfp 关键字标记的方法必须使用严格的浮点计算来生成可再生的结果. 如可把 main 方法标记为
public static strictfp void main(String[] args)
这样, 在 main 方法中的所有指令都将使用严格的浮点计算. 或将一个类标记为 strictfp, 这个类中的所有方法都要使用严格的浮点计算.
以上, 摘自《Java 核心技术 卷I》, 略有修改.
总结:
strictfp, 即 strict float point.
strictfp 可修饰类或方法, 使之使用严格的浮点计算.
严格浮点计算不是没有计算结果没有误差, 相反误差可能更大, 且可能会导致溢出和损耗性能.
若数值计算中不允许有任何舍入误差, 应该使用 BigDecimal 类.