Вычисление sin(x)
index.htm - English text
Focus.zip - архивированная директория.
Рассмотрим следующую программу вычисления sin(x) через обычное разложение в ряд sin(x) = x - x3/3! + x5/5! - x7/7! + ...
/** * Supercompilation of calculation of sin(x) */ public class Sn{ // public static final int iters = 3; // public static final int iters = 100; public static final int iters = 1000; public static double x = 3.141592653589793D / 6; public static void main (String[] args) { double x2n = x; double res = x; double step = 2.0; double znam = -1.0 / 6.0; for (int i=0; i<iters; i++) { x2n = x2n * x * x ; res = res + (x2n * znam); step = step + 2.0; znam = -znam / (step * (step+1.0)); } System.out.println("x = " + x); System.out.println("sin(x) = " + res); } }
Программа вычисляет сумму слагаемых ряда в количестве iters. Переменная iters зафиксирована, и по ней будет происходить специализация. Переменная x для суперкомпилятора не известна (x = 3.141592653589793D / 6 исключительно для контрольных пусков на счет, должно получиться 0.5).
При iters = 3 получается очень хорошая остаточная программа
//-------------------------------------- 0 sec - method Sn.main(java.lang.String[]) //-------------------------------------- 0 sec - postprocessing... public static void main (final java.lang.String[] args_2) { final double sn_x_3 = Sn.x; final double sn_x_4 = Sn.x; final double x2n_9 = sn_x_3 * Sn.x * Sn.x; final double x2n_23 = x2n_9 * Sn.x * Sn.x; final double res_39 = sn_x_4 + x2n_9 * -0.16666666666666666D + x2n_23 * 0.008333333333333333D + x2n_23 * Sn.x * Sn.x * -1.984126984126984e-4D; java.lang.System.out.println("x = " + Sn.x) /*virtual*/; java.lang.System.out.println("sin(x) = " + res_39) /*virtual*/; return; } //-------------------------------------- 0 sec - JScp version 0.0.77
Теперь меняю iters = 100, получаю через 30 секунд программу sn1000.js.
Смотрю количество слагаемых и вижу, что их явно меньше 100.
С целью посмотреть, что произойдет дальше полагаю последовательно iters = 200, iters = 400, iters = 1000.
Время суперкомпиляции увеличивается незначительно, остаточная программа совершенно не меняется !
Здесь мы наблюдаем знание суперкомпилятора о том, что A + 0 = A.
Все описанное можно посмотреть в директории focus приложения Focus.zip.
Перейдем ко второму примеру, расположенному в директории focus2 приложения Focus.zip.
Здесь организуем суммирование ряда для sin(x) с обратного конца.
Будем использовать рекурсию, надеясь, что в остаточной программе рекурсии не будет, и поэтому получатся хорошие коэффициенты ускорения.
Исходная программа
/** * Supercompilation of calculation of sin(x) * Calculation sin(x) through decomposition * sin(x) = x - x^3/3! + x^5/5! - x^7/7! + ... * The return order of addition. */ public class Sn { // public static final int iters = 200; /* 2*Quantity of addition*/ public static final int iters = 2000; /* 2*Quantity of addition*/ public static void main (String[] args) { int iprint1 = 5; int iprint = 100000; for (int ip = 0; ip < iprint1; ip++) { long start = System.currentTimeMillis(); double x = 3.141592653589793D / 6; double res = 0.0; for (int i = 0; i < iprint; i++) { res = sin(x); } System.out.println("x = " + x); System.out.println("sin(x) = " + res); long end = System.currentTimeMillis(); System.out.println("Total time = "+ (end-start)*0.001); } } public static double sin(double x) { return sin1(x, x, 2, 1.0); } /** One step of calculation sin(x) * @param double x - argument sin(x) * @param double x2n - x^(2*n+1) * @param int step - 2*n * @param double znam - +-1/(2*n+1)! */ public static double sin1(double x, double x2n, int step, double znam) { if (step==iters) return 0.0; else return sin1(x, x2n*x*x, step+2, -znam/(step*(step+1))) + x2n*znam; } }
Остаточные программы sn.js одинаковые для iters=100 и для iters-1000.
Если iters=100, то время исполнения исходной программы 1.95 секунды, остаточной программы - 0.70 секунды, ускорение - 2.8 раза.
Теперь меняем iters = 1000, в результате чего остаточная программа не меняется, а исходная будет исполняться в 10 раз дольше.
Время исполнения исходной программы 16.25 секунды, остаточной программы - 0.70 секунды, ускорение - 23.2 раза.
В этом примере много предположений и недостатков, но идея использования таким образом суперкомпиляции - хорошая идея.