Запустите java-классы размером более 64k, чтобы решить нелинейную систему уравнений
Я пытаюсь решить систему нелинейных функций в java. В частности, у меня есть 3 уравнения с тремя неизвестными переменными. Хотя мне удалось решить простые уравнения, моя конечная цель - решить некоторые довольно большие.
Например, каждое уравнение состоит из сотен строк (иногда даже тысяч) в виде:
public static double f2 (double x, double y, double z) {
double result = (0.49*Math.exp(-y - x)*Math.pow(x,2)*
(1 - Math.pow(z,94)*(0.00666 +
0.98*Math.exp(-y - x) + 0.98*Math.exp(-y - x)*
y*x + 0.245*Math.exp(-y - x)*Math.pow(y,2)*
Math.pow(x,2) + 0.02722*
Math.exp(-y - x)*Math.pow(y,3)*Math.pow(x,3) +
0.00170*Math.exp(-y - x)*
Math.pow(y,4)*Math.pow(x,4) + 0.00006*
Math.exp(-y - x)*Math.pow(y,5)*Math.pow(x,5) +
1.89043*Math.pow(10,-6)*Math.exp(-y - x)*
Math.pow(y,6)*Math.pow(x,6) + 3.85802*Math.pow(10,-8)*
Math.exp(-y - x)*Math.pow(y,7)*Math.pow(x,7) +
6.02816*Math.pow(10,-10)*Math.exp(-y - x)*
Math.pow(y,8)*Math.pow(x,8) + 7.44217*Math.pow(10,-12)*
Math.exp(-y - x)*Math.pow(y,9)*Math.pow(x,9) +
7.44217*Math.pow(10,-14)*Math.exp(-y - x)*
Math.pow(y,10)*Math.pow(x,10))))/(0.01333 +
0.98*Math.exp(-y - x)*y +
0.49*Math.exp(-y - x)*Math.pow(y,2) +
0.16333*Math.exp(-y - x)*Math.pow(y,3) +
0.04083*Math.exp(-y - x)*Math.pow(y,4) +
0.00816*Math.exp(-y - x)*Math.pow(y,5) + .....
Проблема в том, что два из моих классов значительно больше, чем 65k, в частности, 650k/class, поэтому я вышел из пределов.
Есть ли способ запустить/скомпилировать мой код, преодолев эти ограничения?
Мои 3 уравнения были сгенерированы с другого языка (wolfram), но мне нужно реализовать свою цель в java (математический/matlab и т.д. не является n опцией).
Этот ответ предполагает использование .properties, но я не могу понять, как это может помочь в моем случае (Слишком большая ошибка компиляции в Java)
Ответы
Ответ 1
Проблема здесь в 64-битном ограничении на байт-код метода, поэтому единственный вариант - разделить вещи. Минимальный подход к этому состоит в том, чтобы идентифицировать большие, извлекаемые последовательности и вытаскивать их. Возьмем, например:
0.98*Math.exp(-y - x) + 0.98*Math.exp(-y - x)*
y*x + 0.245*Math.exp(-y - x)*Math.pow(y,2)*
Math.pow(x,2) + 0.02722*
Math.exp(-y - x)*Math.pow(y,3)*Math.pow(x,3) +
0.00170*Math.exp(-y - x)*
Math.pow(y,4)*Math.pow(x,4) + 0.00006*
Math.exp(-y - x)*Math.pow(y,5)*Math.pow(x,5) +
1.89043*Math.pow(10,-6)*Math.exp(-y - x)*
Math.pow(y,6)*Math.pow(x,6) + 3.85802*Math.pow(10,-8)*
Math.exp(-y - x)*Math.pow(y,7)*Math.pow(x,7) +
6.02816*Math.pow(10,-10)*Math.exp(-y - x)*
Math.pow(y,8)*Math.pow(x,8) + 7.44217*Math.pow(10,-12)*
Поскольку ни одна из этих строк не имеет согласованных фигурных скобок, и мы знаем, что это все одно уравнение (переменные не изменяются в ходе вычисления), их можно безопасно извлечь как блок с идентичными параметрами функции:
public static double a1 (double x, double y, double z) {
return 0.98*Math.exp(-y - x) + 0.98*Math.exp(-y - x)*
y*x + 0.245*Math.exp(-y - x)*Math.pow(y,2)*
Math.pow(x,2) + 0.02722*
Math.exp(-y - x)*Math.pow(y,3)*Math.pow(x,3) +
0.00170*Math.exp(-y - x)*
Math.pow(y,4)*Math.pow(x,4) + 0.00006*
Math.exp(-y - x)*Math.pow(y,5)*Math.pow(x,5) +
1.89043*Math.pow(10,-6)*Math.exp(-y - x)*
Math.pow(y,6)*Math.pow(x,6) + 3.85802*Math.pow(10,-8)*
Math.exp(-y - x)*Math.pow(y,7)*Math.pow(x,7) +
6.02816*Math.pow(10,-10)*Math.exp(-y - x)*
Math.pow(y,8)*Math.pow(x,8) + 7.44217*Math.pow(10,-12);
}
Это можно затем ввести в исходную функцию так:
public static double f2 (double x, double y, double z) {
double result = (0.49*Math.exp(-y - x)*Math.pow(x,2)*
(1 - Math.pow(z,94)*(0.00666 +
a1()*
Math.exp(-y - x)*Math.pow(y,9)*Math.pow(x,9) +
7.44217*Math.pow(10,-14)*Math.exp(-y - x)*
Math.pow(y,10)*Math.pow(x,10))))/(0.01333 +
0.98*Math.exp(-y - x)*y +
0.49*Math.exp(-y - x)*Math.pow(y,2) +
0.16333*Math.exp(-y - x)*Math.pow(y,3) +
0.04083*Math.exp(-y - x)*Math.pow(y,4) +
0.00816*Math.exp(-y - x)*Math.pow(y,5) + .....
Это явно не требует усилий для оптимизации или устранения дублирования; это самый простой способ преодолеть ограничение размера метода.
Ответ 2
Предел 64K применим к методу, поэтому вы можете поместить свой код в разные методы, которые называются один за другим, передавая промежуточный результат.
Если вы достигнете предела размера класса (я не знаю об этом, но в последний раз, когда я столкнулся с этой проблемой, я был в 2000 году и с Java 1.1), вы можете сделать тот же трюк и отделить свой код над несколькими классами. Внутренние классы должны быть в порядке для этого, поэтому вы все равно можете выводить свой код в один исходный файл.
Изменить: вы также можете искать результаты расчета, которые можно использовать повторно. Например, вы часто вычисляете Math.exp(-y - x)
. Ввод этого во временную переменную должен сэкономить место и должен сделать весь расчет значительно быстрее. Кроме того, происходит тот же самый расчет, который можно поместить в свой собственный метод:
0.98*Math.exp(-y - x)*y +
0.49*Math.exp(-y - x)*Math.pow(y,2) +
0.16333*Math.exp(-y - x)*Math.pow(y,3) +
0.04083*Math.exp(-y - x)*Math.pow(y,4) +
0.00816*Math.exp(-y - x)*Math.pow(y,5) + ...
может быть изменено на следующее (вводится непосредственно в этот текст, поэтому могут быть ошибки компиляции IRL):
private static double calcLoop(double x, double y, int max) {
double expVal = Math.exp(-y - x);
double startVal = 0.98;
double sum = startVal * y
for (int i = 2; i <= max; i++) {
startVal = startVal / i;
sum += startVal * Math.pow(y, i);
}
return sum * expVal;
}
Этот метод также "оптимизировал" вычисление, только умножая полученную сумму на expVal
Ответ 3
Java говорит, что нужно быть модульным и думать с точки зрения объектов. Создайте меньшие классы и попытайтесь повторно использовать существующий код и при необходимости переопределите.
В вашем коде может быть много проблем. Из фрагмента, который вы опубликовали здесь, и моего прошлого опыта, я бы предложил следующее: -
-
Не помещайте константы в один и тот же класс, если их больше 3-4. Просто создайте еще один класс, который просто поддерживает такие константы.
-
Никогда не помещайте данные внутри класса, кроме некоторых необходимых инициализаций.
-
Разбить класс на несколько классов.
-
Попробуйте найти повторяющиеся сегменты кода/выражения внутри уравнения и вытащите их методу. Вы можете найти даже вложенные повторяющиеся операторы или сегменты. Подумайте о том, что ваше математическое уравнение сформировано из нескольких вызовов методов, которые могут включать методы, вызывающие только вызовы других наборов методов.
-
Как только вы сможете вывести их методу, вы можете легко вывести их в класс.
-
Используйте статический импорт, если это возможно, но никогда не пытались сохранить некоторое пространство. Следовательно, бит экспериментальный.
Надеюсь, что это поможет!