0%

Java中的strictfp关键字

Java中的strictfp关键字

背景

绝大多数Java程序员都没有使用过strictfp关键字, 大多数的Java程序员甚至都不知道这个关键字。 其原因跟strictfp的作用有关, 因为绝大多数的Java程序员都在做x86/64平台下的web应用,抑或也使用其他服务平台。 仅从其后,同样不太流行的Java关键字还有transient

strictfp的作用

正是因为strictfp的作用导致Java程序员们甚至都没用过它。

在更早的Java版本中,浮点数本身就是严格的,但近代java版本(也不怎么近,就java1.2和之后)为了更高效的运算,默认情况下,Java的浮点数运算是平台相关的,。jvm会依据当前平台的机器特性选用适合的浮点数处理方式,而不是严格按照标准进行计算,例如,在一些低性能嵌入式设备上,Java会利用更高效的浮点数运算指令进行浮点数计算,它的结果和精度都与高性能的硬件上不同。

由于Java实现不再广泛使用x87浮点,因此有一个主动提议再次使所有浮点运算严格,有效地恢复1.2之前的语义。

strictfp允许程序员强制指定浮点数的运算遵循严格规范。当运行在不直接支持指令运算的硬件上时,Java会使用软件的形式去进行严格浮点数计算,这样会大大降低浮点数运行效率,但好处也是显而易见的, 浮点数运算的结果可知可控且各平台一致

在没有溢出或下溢的情况下,有或没有strictfp的结果没有差异。如果重复性是必要的,则strictfp修饰符可用于确保在所有平台上的相同位置发生溢出和下溢。如果没有strictfp修饰符,中间结果可能会使用更大的指数范围。

该strictfp修改由代表所有的中间值作为IEEE单精度和双精度值,如发生在早期版本的JVM实现这一目的。

strictfp 关键字的用法

strictfp可用于修饰 类、非抽象方法或者接口。 除此之外均不可用,尤其是直觉上的用于属性和构造器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public strictfp class ScientificCalculator {
// ...

public double sum(double value1, double value2) {
return value1 + value2;
}

public double diff(double value1, double value2) {
return value1 - value2;
}
}

public strictfp void calculateMarksPercentage() {
// ...
}

public strictfp interface Circle {
double computeArea(double radius);
}

strictfp的修饰作用不会延伸到其子类(实现类)和子类方法中,除非是内部类。被strictfp修饰的类的子类如果要保持严格浮点计算的特性,那么,需要在它本身再次声明strictfp。 联系到抽象方法无法使用strictfp修饰,这一点比较好理解。

但是对于接口,strictfp存在的意义仅为声明其默认方法为浮点运算严格的,一旦接口没有默认方法,它被strictfp修饰意义就仅剩其内部类了,然而接口的内部类使用并不常见。

何时使用strictfp

  1. 当在意浮点数运算的确定性和精度时,需要使用strictfp

在有些平台上,浮点数为了快速计算并不严格遵循IEEE754的规范,这可能导致浮点数运算结果在精度上与规范要求的不同,当我们的代码需要对这部分作出保证时,就要使用strictfp了。

  1. 代码需要运行在不同的平台上产生相同的行为时,需要使用strictfp

随着分布式技术的投入使用和异构平台协同,同样的代码可能同时运行在不同平台的机器上协同工作,此时保证其计算结果的相同就尤为重要了,这种情况下,需要使用strictfp

strictfp会影响代码性能么?

会,但不是全部

在回答这个问题上,我没有做大量的实验来验证,但从查阅到的资料和对strictfp实现的分析中得出这个结论。

jvm在目标平台上往往会采取更高效的浮点数运算方法,这一般意味着硬件提供的快速的浮点数运算指令。这类指令往往不遵循IEEE规范但更高效。高效正式这类指令存在的重要原因(否则为什么不严格遵守规范呢?),高效不一定体现在计算速度上,也可以体现在硬件设计复杂性更低上,可以使用更少的门电路实现乘法器。

使用了strictfp修饰类后,往往会造成jvm无法使用这类更加“高效”的指令,在简陋指令平台甚至需要使用软件控制来完成浮点运算,这样往往会大幅降低计算效率(一旦使用软件控制,效率降低可达几十倍)。

但是,对于高端的现代平台,往往都提供了高效且严格遵循IEEE754规范的乘法器指令, jvm即使没有被告知strictfp本身就会使用这些指令,所以strictfp 在这类平台上是不会影响执行效率的。