Запустите 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. Просто создайте еще один класс, который просто поддерживает такие константы.

  • Никогда не помещайте данные внутри класса, кроме некоторых необходимых инициализаций.

  • Разбить класс на несколько классов.

  • Попробуйте найти повторяющиеся сегменты кода/выражения внутри уравнения и вытащите их методу. Вы можете найти даже вложенные повторяющиеся операторы или сегменты. Подумайте о том, что ваше математическое уравнение сформировано из нескольких вызовов методов, которые могут включать методы, вызывающие только вызовы других наборов методов.

  • Как только вы сможете вывести их методу, вы можете легко вывести их в класс.

  • Используйте статический импорт, если это возможно, но никогда не пытались сохранить некоторое пространство. Следовательно, бит экспериментальный.

Надеюсь, что это поможет!