【发布时间】:2013-11-02 23:09:31
【问题描述】:
我的代码:
import java.math.BigDecimal;
public class ScienceFair {
private static long NewtonMethod()
{
BigDecimal TWO = new BigDecimal(2);
BigDecimal SQRT_TWO = new BigDecimal("1.4142135623730950488016887242096980785696718753769480731766797379907324784621070388503875343276415727");
BigDecimal TOLERANCE = BigDecimal.ONE.scaleByPowerOfTen(-100);
long start = System.nanoTime();
BigDecimal a = new BigDecimal(1);
while(a.subtract(SQRT_TWO).abs().compareTo(TOLERANCE) >= 0) {
a = a.add(TWO.divide(a, 100, BigDecimal.ROUND_HALF_UP)).divide(TWO);
}
return System.nanoTime() - start;
}
private static long MidpointMethod()
{
BigDecimal TWO = new BigDecimal(2);
BigDecimal SQRT_TWO = new BigDecimal("1.4142135623730950488016887242096980785696718753769480731766797379907324784621070388503875343276415727");
BigDecimal TOLERANCE = BigDecimal.ONE.scaleByPowerOfTen(-100);
long start = System.nanoTime();
BigDecimal a = new BigDecimal(1);
BigDecimal b = new BigDecimal(2);
while(a.add(b).divide(TWO).subtract(SQRT_TWO).abs().compareTo(TOLERANCE) >= 0) {
if(a.multiply(a).subtract(TWO).abs().compareTo(b.multiply(b).subtract(TWO).abs()) == 1)
{
a = a.add(b).divide(TWO);
}
else
{
b = a.add(b).divide(TWO);
}
}
return System.nanoTime() - start;
}
private static long SecantMethod()
{
BigDecimal TWO = new BigDecimal(2);
BigDecimal SQRT_TWO = new BigDecimal("1.4142135623730950488016887242096980785696718753769480731766797379907324784621070388503875343276415727");
BigDecimal TOLERANCE = BigDecimal.ONE.scaleByPowerOfTen(-100);
long start = System.nanoTime();
BigDecimal a = new BigDecimal(1);
BigDecimal b = new BigDecimal(2);
BigDecimal b_old = new BigDecimal(2);
while(a.add(b).divide(TWO).subtract(SQRT_TWO).abs().compareTo(TOLERANCE) >= 0) {
b_old = b;
b = a.multiply(b).add(TWO).divide(a.add(b), 100, BigDecimal.ROUND_HALF_UP);
a = b_old;
}
return System.nanoTime() - start;
}
public static void main(String[] args) {
double a = 0;
int trials = 100;
for(int i=1; i<= trials; i++)
{
a += (NewtonMethod() / 10e6);
}
System.out.printf("Newton's Method: %f\n", a/trials);
a = 0;
for(int i=1; i<= trials; i++)
{
a += (MidpointMethod() / 10e6);
}
System.out.printf("Midpoint Method: %f\n", a/trials);
a = 0;
for(int i=1; i<= trials; i++)
{
a += (SecantMethod() / 10e6);
}
System.out.printf("Secant Method: %f\n", a/trials);
}
}
旨在运行牛顿法、中点法和正割法,以找出逼近小数点后 2 到 100 位的平方根所需的时间。
它对每个测试运行 100 次试验,然后对它们进行平均以输出所用的毫秒数。
中点法总是在 1.5 秒左右。但是,牛顿法和正割法相差很大,从 0.08 到 0.14 秒(大约一倍)不等。为什么会这样?
编辑:这是我现在尝试的(仅适用于 NewtonMethod)
public class ScienceFairTwo {
public static void main(String[] args) throws Exception {
Runnable NewtonMethod = new Runnable()
{
public void run()
{
BigDecimal TWO = new BigDecimal(2);
BigDecimal SQRT_TWO = new BigDecimal("1.4142135623730950488016887242096980785696718753769480731766797379907324784621070388503875343276415727");
BigDecimal TOLERANCE = BigDecimal.ONE.scaleByPowerOfTen(-100);
long start = System.nanoTime();
BigDecimal a = new BigDecimal(1);
while(a.subtract(SQRT_TWO).abs().compareTo(TOLERANCE) >= 0) {
a = a.add(TWO.divide(a, 100, BigDecimal.ROUND_HALF_UP)).divide(TWO);
}
}
};
System.out.println("Newton's Method: " + new Benchmark(NewtonMethod));
}
}
【问题讨论】:
-
尝试在不测量的情况下运行 1000 次试验,然后在测量的情况下运行 1000 次试验。 JIT 起着重要的作用,它需要多次执行来检测热点并编译它们。此外,您的测试分配了许多对象,因此 GC 可能会启动缓慢的测试之一。我建议使用像 Caliper 这样的真正的微基准测试框架。