Reputation: 135
My code:
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);
}
}
is designed to run the Newton Method, the Midpoint Method, and the Secant Method to find the amount of time it takes to approximate the square root of two to 100 decimal places.
It runs 100 trials of each of them, and averages them to output the number of milliseconds taken.
The Midpoint method is always around 1.5 seconds. However, the Newton method and the Secant method vary greatly, ranging from 0.08 to 0.14 seconds (about double). Why is this happening?
Edit: Here is what I tried now (only for 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));
}
}
Upvotes: 1
Views: 161
Reputation: 19837
In general, benchmarking Java code is difficult. Your simple benchmark is not reliable enough.
I can see three problems with your approach (there can be more):
java.math.BigDecimal
is unlucky, because it wastes time for loading that class into memory. Other methods don't have this penalty - BigDecimal
is already loaded.I recommend you two things:
(When you do the benchmark correctly - post a link in the comment. I would like to see how your methods perform)
Upvotes: 4