Вычисление 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 раза.
В этом примере много предположений и недостатков, но идея использования таким образом суперкомпиляции - хорошая идея.