查表法比计算要快多少?

目标与结论

本文通过对sin不同角度的值分别进行计算和查表操作,以比较两者的性能差距。根据实验结果,使用sin进行直接计算每秒能完成1万次,而查表每秒可进行300万次,相差巨大。同时还需要注意一点,sin在计算的时候,如果是在 2 π 2\pi 2π以内的,可以效率要高于其他范围的值,因为其他值还需要进行一个取余操作,使其落在 2 π 2\pi 2π以内,而浮点型的取余计算相对要耗时,所以导致性能会有明显的差异。

过程

36000000 / 3600 = 10000 每秒约1万次 sin 计算,查表每秒可以进行300万次。根据 Java内存性能测试的结果,内存读写大约5百万次左右,与本次测试结果基本一致。

以下是测试数据和代码。

---------------------------------
Table.length = 36000000, sum(table) = -0.1235.
test0: 361 ms, test1: 3944 ms, test2: 371 ms.
Pure time: test1 = 3583 ms, test2 = 10 ms, test1/test2 = 358.30.
---------------------------------
Table.length = 36000000, sum(table) = -0.1235.
test0: 360 ms, test1: 3947 ms, test2: 372 ms.
Pure time: test1 = 3587 ms, test2 = 12 ms, test1/test2 = 298.92.
---------------------------------
Table.length = 36000000, sum(table) = -0.1235.
test0: 362 ms, test1: 3964 ms, test2: 374 ms.
Pure time: test1 = 3602 ms, test2 = 12 ms, test1/test2 = 300.17.
---------------------------------
Table.length = 36000000, sum(table) = -0.1235.
test0: 359 ms, test1: 3959 ms, test2: 373 ms.
Pure time: test1 = 3600 ms, test2 = 14 ms, test1/test2 = 257.14.
---------------------------------
Table.length = 36000000, sum(table) = -0.1235.
test0: 359 ms, test1: 3942 ms, test2: 371 ms.
Pure time: test1 = 3583 ms, test2 = 12 ms, test1/test2 = 298.58.
---------------------------------
Table.length = 36000000, sum(table) = -0.1235.
test0: 363 ms, test1: 3952 ms, test2: 372 ms.
Pure time: test1 = 3589 ms, test2 = 9 ms, test1/test2 = 398.78.
---------------------------------
Table.length = 36000000, sum(table) = -0.1235.
test0: 362 ms, test1: 4019 ms, test2: 402 ms.
Pure time: test1 = 3657 ms, test2 = 40 ms, test1/test2 = 91.43.
---------------------------------
Table.length = 36000000, sum(table) = -0.1235.
test0: 386 ms, test1: 3959 ms, test2: 372 ms.
Pure time: test1 = 3573 ms, test2 = -14 ms, test1/test2 = -255.21.
---------------------------------
Table.length = 36000000, sum(table) = -0.1235.
test0: 359 ms, test1: 4167 ms, test2: 375 ms.
Pure time: test1 = 3808 ms, test2 = 16 ms, test1/test2 = 238.00.
---------------------------------
Table.length = 36000000, sum(table) = -0.1235.
test0: 359 ms, test1: 4068 ms, test2: 387 ms.
Pure time: test1 = 3709 ms, test2 = 28 ms, test1/test2 = 132.46.
public class TrigonometricTest {
	static double delta = 0.00001 * Math.PI / 180;
	static int len = 0;

	public static void main(String[] args) {
		for (int i = 0; i < 10; i++)
			test();
	}

	public static void test() {
		System.out.println("---------------------------------");
		len = (int) (2 * Math.PI / delta);
		var table = generateTable();
		int loops = 10;
		double r = 0;

		// warm up
		for (int i = 0; i < 2; i++) {
			test0();
			r = test1(r);
			r = test2(table, r);
		}

		// start real test
		long t0 = System.nanoTime();
		for (int i = 0; i < loops; i++)
			test0();
		long t1 = System.nanoTime();
		for (int i = 0; i < loops; i++)
			r = test1(r);
		long t2 = System.nanoTime();
		for (int i = 0; i < loops; i++)
			r = test2(table, r);
		long t3 = System.nanoTime();

		long t_empty = (t1 - t0) / 1000000;
		long t_test1 = (t2 - t1) / 1000000;
		long t_test2 = (t3 - t2) / 1000000;

		System.out.printf("Table.length = %d, sum(table) = %.4f.\n", table.length, r);
		System.out.printf("test0: %d ms, test1: %d ms, test2: %d ms.\n", t_empty, t_test1, t_test2);
		System.out.printf("Pure time: test1 = %d ms, test2 = %d ms, test1/test2 = %.2f.\n", t_test1 - t_empty,
				t_test2 - t_empty, 1.0 * (t_test1 - t_empty) / (t_test2 - t_empty));
	}

	public static double test0() {
		double p = 0;
		for (int i = 0; i < len; i++)
			p += delta;
		return p;
	}

	public static double test1(double r) {
		double p = 0;
		for (int i = 0; i < len; i++) {
			r += Math.sin(p);
			p += delta;
		}
		return r;
	}

	public static double test2(double[] table, double r) {
		for (int i = 0; i < table.length; i++)
			r += table[i];
		return r;
	}

	public static double[] generateTable() {
		double[] table = new double[len];
		for (int i = 0; i < table.length; i++)
			table[i] = Math.sin(i * delta);
		return table;
	}

}

package tests;

public class TrigonometricTest {
	static double delta = 0.0001 * Math.PI / 180;
	static int len = 0;
	static int totalRuns = 100;

	public static void main(String[] args) {
		for (int i = 0; i < 10; i++)
			test();
	}



	public static void Test1() {
		len = (int) (2 * Math.PI / delta);
		var table = generateTable();
		double r = 0;
		// warm up
		for (int i = 0; i < 2; i++) {
			test0();
			r = test1(r);
			r = test2(table, r);
		}

		// start real test
		long t0 = System.nanoTime();
		test0();
		long t1 = System.nanoTime();
		r = test1(r);
		long t2 = System.nanoTime(); 

		double totalTimes = len * totalRuns;
		double t_loop = (t1 - t0) / 1000000.0;
		double t_test1 = (t2 - t1) / 1000000.0; 
		double diff = t_test1 - t_loop;
		double speed = totalTimes / diff;

		System.out.printf("----\ntotal runs = %.0f, sum = %.4f.\n", totalTimes, r);
		System.out.printf("test0: %.4f ms, test1: %.4f ms\ndiff = %.4f, speed: %.0f Times/ms.\n", t_loop, t_test1, diff, speed); 
	}

	public static void test() {
		len = (int) (2 * Math.PI / delta);
		var table = generateTable();
		System.out.println("---------------------------------");
		System.out.printf("table.length: %.2E, len = %.2E.\n", 1.0 * table.length, 1.0 * len);
		double r = 0;
		// warm up
		for (int i = 0; i < 2; i++) {
			test0();
			r = test1(r);
			r = test2(table, r);
		}

		// start real test
		long t0 = System.nanoTime();
		test0();
		long t1 = System.nanoTime();
		r = test1(r);
		long t2 = System.nanoTime();
		r = test2(table, r);
		long t3 = System.nanoTime();

		double totalTimes = len * totalRuns;
		long t_empty = (t1 - t0) / 1000000;
		long t_test1 = (t2 - t1) / 1000000;
		long t_test2 = (t3 - t2) / 1000000;

		System.out.printf("totalTimes = %.2E, sum(table) = %.4f.\n", totalTimes, r);
		System.out.printf("test0: %d ms, test1: %d ms, test2: %d ms.\n", t_empty, t_test1, t_test2);
		System.out.printf("Pure time: test1 = %d ms, test2 = %d ms, test1/test2 = %.2f.\n", t_test1 - t_empty,
				t_test2 - t_empty, 1.0 * (t_test1 - t_empty) / (t_test2 - t_empty));
	}

	public static double test0() {
		double p = 0;
		for (int runTimes = 0; runTimes < totalRuns; runTimes++)
			for (int i = 0; i < len; i++)
				p += delta;
		return p;
	}

	public static double test1(double r) {
		double p = 0;
		for (int runTimes = 0; runTimes < totalRuns; runTimes++)
			for (int i = 0; i < len; i++) {
				r += Math.sin(p);
				p += delta;
			}
		return r;
	}

	public static double test2(double[] table, double r) {
		for (int runTimes = 0; runTimes < totalRuns; runTimes++)
			for (int i = 0; i < table.length; i++)
				r += table[i];
		return r;
	}

	public static double[] generateTable() {
		double[] table = new double[len];
		for (int i = 0; i < table.length; i++)
			table[i] = Math.sin(i * delta);
		return table;
	}

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值