Возможно ли переопределить аргументы конструктора?

Имеется класс для монотонной интерполяции Эрмита, работает:

public class CubeSpline {
    private final double[] mX;
    private final double[] mY;
    private final double[] mM; // это касательные для точек х и у

    protected CubeSpline(double[] x, double[] y, double[] m) {
        mX = x;
        mY = y;
        mM = m;
    }

    public static CubeSpline createMonotoneCubicSpline(double x[], double[] y) {
        if (x == null || y == null || x.length != y.length || x.length < 2) {
            throw new IllegalArgumentException("There must be at least two control "
                    + "points and the arrays must be of equal length.");
        }
        final int n = x.length;
        double[] d = new double[n - 1]; // could optimize this out
        double[] m = new double[n];

        // Compute slopes of secant lines between successive points.
        for (int i = 0; i < n - 1; i++) {
            double h = x[i + 1] - x[i];
            if (h <= 0) {
                throw new IllegalArgumentException("Значения х должны всегда возрастать.");
            }
            d[i] = (y[i + 1] - y[i]) / h;
        }

        // Initialize the tangents as the average of the secants.
        m[0] = d[0];
        for (int i = 1; i < n - 1; i++) {
            m[i] = (d[i - 1] + d[i]) * 0.5;
        }
        m[n - 1] = d[n - 2];

        // Update the tangents to preserve monotonicity.
        for (int i = 0; i < n - 1; i++) {
            if (d[i] == 0) { // successive Y values are equal
                m[i] = 0;
                m[i + 1] = 0;
            }
            double a = m[i] / d[i];
            double b = m[i + 1] / d[i];

            if (a <= 0)
                m[i] = 0.0;

            if (b <= 0)
                m[i + 1] = 0.0;

            double h = (double) Math.hypot(a, b);
            if (h > 3) {
                double t = 3 / h;
                m[i] = t * a * d[i];
                m[i + 1] = t * b * d[i];
            }
        }
        return new CubeSpline(x, y, m);
    }

    /**
     * Interpolates the value of Y = f(X) for given X. Clamps X to the domain of the spline.
     *
     * @param x The X value.
     * @return The interpolated Y = f(X) value.
     */
    public double interpolate(double x) {
        // Handle the boundary cases.
        final int n = mX.length;
        if (Double.isNaN(x)) {
            return x;
        }
        if (x <= mX[0]) {
            return mY[0];
        }
        if (x >= mX[n - 1]) {
            return mY[n - 1];
        }

        // Find the index 'i' of the last point with smaller X.
        // We know this will be within the spline due to the boundary tests.
        int i = 0;
        while (x >= mX[i + 1]) {
            i += 1;
            if (x == mX[i]) {
                return mY[i];
            }
        }

        // Perform cubic Hermite spline interpolation.
        double h = mX[i + 1] - mX[i];
        double t = (x - mX[i]) / h;
        return (mY[i] * (1 + 2 * t) + h * mM[i] * t) * (1 - t) * (1 - t)
                + (mY[i + 1] * (3 - 2 * t) + h * mM[i + 1] * (t - 1)) * t * t;
    }
}

Через статический метод передается 2 массива из вложенного в основной класс статического класса. Все это инкапсулировано в разные методы, возвращающие результат интерполяции. Так получилось, что некоторые массивы приходится выстраивать в обратном порядке, иначе интерполяция не работает. И если один и тот же метод вызывается 2 раза, то порядок массива тоже изменяется 2 раза и соответственно вылетает ошибка. Возможно как-то этого избежать?

public class Main {
    public static void main(String[] args) {
        Calculates calc = new Calculates();
        System.out.println("Остаток в л" + calc.massToVolume(cubeOm, cubeOmMassPerc));
        System.out.println("Количество диста в л " + calc.massToVolume(distAm, distPer)); //вот тут возникает двойное применение метода massSwap();

        public static class Calculates {
            CubeSpline csp;
            private double massToVolume(double mass, double massPerc) //объем в массу
            {
                //csp = new CubeSpline(null,null,null); так не работает
                double m;
                csp = CubeSpline.createMonotoneCubicSpline(massSwap(ArrayInit.spiritPercentsMass), massSwap(ArrayInit.spiritPercentsVol));
                double volPerc = csp.interpolate(massPerc);
                csp = CubeSpline.createMonotoneCubicSpline(massSwap(ArrayInit.densityWaterSpirit), massSwap(ArrayInit.massPercForDensity));
                m = (mass / 10000) / csp.interpolate(volPerc);
                return Math.ceil(m * 10000) / 10000;
            }

            public static double[] massSwap(double[] a) {
                double b;
                for (int i = 0; i < a.length / 2; i++) {
                    b = a[a.length - i - 1];
                    a[a.length - i - 1] = a[i];
                    a[i] = b;
                }
                return a;
            }
        }
    }
}

Ответы (1 шт):

Автор решения: Дмитрий Никифоров

Много кода и сложно понять вопрос. При работе над минимальным, самодостаточным и воспроизводимым примером часто можно самому справиться с возникшим затруднением. Насколько я понял, ваша проблема в том, что вы при обоих вызовах createMonotoneCubicSpline в качестве параметров передаёте результаты вызовов makeSwap. Зачем так делать?

Варианты решения из моего понимания вопроса:

  1. Один раз вызовите makeSwap до передачи параметров в createMonotoneCubicSpline.

    massSwap(a);
    massSwap(b);
    ...
    csp = CubeSpline.createMonotoneCubicSpline(a, b);
    
  2. Создайте новый объект с обратным порядком элементов, работайте с ним.

    double[] reversedA = massSwap(Arrays.copyOf(a, a.length));
    ...
    csp = CubeSpline.createMonotoneCubicSpline(reversedA, reversedB);
    
  3. Не разворачивайте массив, а идите по нему в обратную сторону там, где это нужно.

Лучше сделать сигнатуру public static void massSwap(double[] a), так понятнее, что метод меняет свой аргумент, а не возвращает развёрнутую копию.

→ Ссылка