显然java.lang.StrictMath
包含其他功能(双曲线等)java.lang.Math
但没有,但两个库中的功能是否存在差异?
coo*_*ird 69
Math
该类的Javadoc 提供了有关两个类之间差异的一些信息:
与类的某些数值方法不同,类
StrictMath
的等效函数的所有实现Math
都未定义为返回逐位相同的结果.这种放松允许在不需要严格再现性的情况下实现性能更好的实施.默认情况下,许多
Math
方法只是StrictMath
为其实现调用等效方法 .鼓励代码生成器使用特定于平台的本机库或微处理器指令(如果可用),以提供更高性能的Math
方法实现 .这种更高性能的实现仍然必须符合规范Math
.
因此,Math
该类列出了某些操作应该执行的操作的规则,但是它们并不要求在库的所有实现中返回完全相同的结果.
这允许库的特定实现返回类似的,但是例如,如果Math.cos
调用类,则不是完全相同的结果.这将允许特定于平台的实现(例如使用x86浮点,例如,SPARC浮点),这可能会返回不同的结果.
(有关特定于平台的实现的一些示例,请参阅Wikipedia中Sine文章的" 软件实现"部分.)
但是,StrictMath
由不同实现返回的结果必须返回相同的结果.对于需要在不同平台上重现结果的情况,这将是合乎需要的.
z00*_*0bs 17
你检查过源代码了吗?java.lang.Math
委托了许多方法java.lang.StrictMath
.
例:
public static double cos(double a) {
return StrictMath.cos(a); // default impl. delegates to StrictMath
}
Run Code Online (Sandbox Code Playgroud)
小智 15
@ntoskrnl作为一个正在使用JVM内部的人,我想说你的观点是"内在函数不一定与StrictMath方法的行为相同".为了找出(或证明)它,我们可以写一个简单的测试.
就拿Math.pow
例如,对于检查的java.lang.Math.pow Java代码(双一,双二),我们将看到:
public static double pow(double a, double b) {
return StrictMath.pow(a, b); // default impl. delegates to StrictMath
}
Run Code Online (Sandbox Code Playgroud)
但是JVM可以通过内部函数或运行时调用自由地实现它,因此返回的结果可能与我们期望的结果不同StrictMath.pow
.
而下面的代码显示了这个电话Math.pow()
对StrictMath.pow()
//Strict.java, testing StrictMath.pow against Math.pow
import java.util.Random;
public class Strict {
static double testIt(double x, double y) {
return Math.pow(x, y);
}
public static void main(String[] args) throws Exception{
final double[] vs = new double[100];
final double[] xs = new double[100];
final double[] ys = new double[100];
final Random random = new Random();
// compute StrictMath.pow results;
for (int i = 0; i<100; i++) {
xs[i] = random.nextDouble();
ys[i] = random.nextDouble();
vs[i] = StrictMath.pow(xs[i], ys[i]);
}
boolean printed_compiled = false;
boolean ever_diff = false;
long len = 1000000;
long start;
long elapsed;
while (true) {
start = System.currentTimeMillis();
double blackhole = 0;
for (int i = 0; i < len; i++) {
int idx = i % 100;
double res = testIt(xs[idx], ys[idx]);
if (i >= 0 && i<100) {
//presumably interpreted
if (vs[idx] != res && (!Double.isNaN(res) || !Double.isNaN(vs[idx]))) {
System.out.println(idx + ":\tInterpreted:" + xs[idx] + "^" + ys[idx] + "=" + res);
System.out.println(idx + ":\tStrict pow : " + xs[idx] + "^" + ys[idx] + "=" + vs[idx] + "\n");
}
}
if (i >= 250000 && i<250100 && !printed_compiled) {
//presumably compiled at this time
if (vs[idx] != res && (!Double.isNaN(res) || !Double.isNaN(vs[idx]))) {
System.out.println(idx + ":\tcompiled :" + xs[idx] + "^" + ys[idx] + "=" + res);
System.out.println(idx + ":\tStrict pow :" + xs[idx] + "^" + ys[idx] + "=" + vs[idx] + "\n");
ever_diff = true;
}
}
}
elapsed = System.currentTimeMillis() - start;
System.out.println(elapsed + " ms ");
if (!printed_compiled && ever_diff) {
printed_compiled = true;
return;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
我用OpenJDK 8u5-b31运行了这个测试,结果如下:
10: Interpreted:0.1845936372497491^0.01608930867480518=0.9731817015518033
10: Strict pow : 0.1845936372497491^0.01608930867480518=0.9731817015518032
41: Interpreted:0.7281259501809544^0.9414406865385655=0.7417808233050295
41: Strict pow : 0.7281259501809544^0.9414406865385655=0.7417808233050294
49: Interpreted:0.0727813262968815^0.09866028976654662=0.7721942440239148
49: Strict pow : 0.0727813262968815^0.09866028976654662=0.7721942440239149
70: Interpreted:0.6574309575966407^0.759887845481148=0.7270872740201638
70: Strict pow : 0.6574309575966407^0.759887845481148=0.7270872740201637
82: Interpreted:0.08662340816125613^0.4216580281197062=0.3564883826345057
82: Strict pow : 0.08662340816125613^0.4216580281197062=0.3564883826345058
92: Interpreted:0.20224488115245098^0.7158182878844233=0.31851834311978916
92: Strict pow : 0.20224488115245098^0.7158182878844233=0.3185183431197892
10: compiled :0.1845936372497491^0.01608930867480518=0.9731817015518033
10: Strict pow :0.1845936372497491^0.01608930867480518=0.9731817015518032
41: compiled :0.7281259501809544^0.9414406865385655=0.7417808233050295
41: Strict pow :0.7281259501809544^0.9414406865385655=0.7417808233050294
49: compiled :0.0727813262968815^0.09866028976654662=0.7721942440239148
49: Strict pow :0.0727813262968815^0.09866028976654662=0.7721942440239149
70: compiled :0.6574309575966407^0.759887845481148=0.7270872740201638
70: Strict pow :0.6574309575966407^0.759887845481148=0.7270872740201637
82: compiled :0.08662340816125613^0.4216580281197062=0.3564883826345057
82: Strict pow :0.08662340816125613^0.4216580281197062=0.3564883826345058
92: compiled :0.20224488115245098^0.7158182878844233=0.31851834311978916
92: Strict pow :0.20224488115245098^0.7158182878844233=0.3185183431197892
290 ms
Run Code Online (Sandbox Code Playgroud)
请注意,Random
它用于生成x和y值,因此您的里程数会因不同的运行而异.但好消息是,至少编译版本的结果Math.pow
与那些解释版本相匹配Math.pow
.(偏离主题:即使这种一致性仅在2012年通过OpenJDK方面的一系列错误修复实施.)
原因?
嗯,这是因为OpenJDK使用内在函数和运行时函数来实现Math.pow
(和其他数学函数),而不仅仅是执行Java代码.主要目的是利用x87指令,以便提高计算性能.因此,StrictMath.pow
永远不会Math.pow
在运行时调用(对于我们刚才使用的OpenJDK版本,确切地说).
根据Math
课堂上的Javadoc (上面引用@coobird),这种规避是完全合法的:
Math类包含执行基本数值运算的方法,例如基本指数,对数,平方根和三角函数.
与StrictMath类的某些数值方法不同,类Math的等效函数的所有实现都未定义为返回逐位相同的结果.这种放松允许在不需要严格再现性的情况下实现性能更好的实施.
默认情况下,许多Math方法只是在StrictMath中调用等效方法来实现它们.鼓励代码生成器使用特定于平台的本机库或微处理器指令(如果可用),以提供更高性能的Math方法实现.此类更高性能的实现仍必须符合Math的规范.
结论呢?那么,对于具有动态代码生成的语言(如Java),请确保您从"静态"代码中看到的内容与运行时执行的内容相匹配.你的眼睛有时会误导你.
归档时间: |
|
查看次数: |
18112 次 |
最近记录: |