Math-модифицированная функция pow для дробных показателей и отрицательных базисов - PullRequest
1 голос
/ 15 июня 2019

Я заметил, что калькуляторы и графические программы, такие как Desmos, Geogebra или Google (поиск в Google x ^ (1/3)) должны иметь модифицированную версию функции Math.pow (), которая позволяет им строить некоторые отрицательные и дробные основания показатели, которые в противном случае были бы неопределенными, используя обычную функцию Math.pow ().

Я пытаюсь воссоздать эту модифицированную функцию pow, чтобы я мог построить отсутствующие участки графиков, например, $ x ^ {\ frac {1} {3}} $, где $ x <0 $ </p>

Моя попытка

Я не знаю, как эта модифицированная функция pow называется в компьютерной науке или математике, поэтому я не могу найти ссылки, которые помогли бы создать надежную и оптимизированную версию. Вместо этого я попытался создать свою собственную версию с помощью класса Fraction из библиотеки Apache math3, чтобы определить некоторые условные операторы, например, когда числитель и знаменатель являются четными или нечетными для дробных показателей.

В моей версии есть несколько проблем, которые я опишу, и в них могут отсутствовать некоторые дополнительные условия, которые я не рассмотрел и которые могут привести к ошибкам.

    /* Main Method */
    public static void main(String[] args) {
        double xmin = -3;
        double xmax = 3;
        double epsilon = 0.011;

        /* print out x,y coordinates for plot */
        for (double x = xmin; x <= xmax; x += epsilon){
            System.out.println(x+","+f(x));
        }
    }

    /* Modified Power Function*/
    private static double pow2(double base, double exponent){
        boolean negativeBase = base < 0;

        /* exponent is an integer and base non-negative */
        if (exponent == ((int) exponent) && !negativeBase){
            /* use regular pow function */
            return Math.pow(base, exponent);
        }

        Fraction fraction;
        try {
            fraction = new Fraction(exponent, 1000); /* maxDenominator of 1000 for speed */
        } catch (FractionConversionException e){
            return Double.NaN;
        }

        /* updated: irrational exponent */
        if (exponent != fraction.doubleValue()){
            /* handles irrational exponents like π which cannot be reduced to fractions.
             * depends heavily on the maxDenominator value set above.
             * With a maxDenominator of 1000, fractions like 1/33333 who's denominator has greater then 4 digits
             * will be considered as irrational. To avoid this, increase maxDenominator to 10000 but will slow down performance.
             * That's the trade off with this part of the algorithm.
             * Also this condition helps clear up a lot the mess on a plot.
             * If the plot is centered at exactly origin (0,0) the messy artifacts may appear, but by offsetting
             * the view of the plot slightly from the origin will make it disappear
             * or maybe it has more to do with the stepsize epsilon (0.01 (clean number) vs 0.011 (irregular number))
             * */
            return Math.pow(base, exponent);
        }

        if (fraction.getDenominator() % 2 == 0){
            /* if even denominator */
            if (negativeBase){
                return Double.NaN;
            }
        } else {
            /* if odd denominator, allows for negative bases */

            if (negativeBase){
                if (fraction.getNumerator() % 2 == 0){
                    /* if even numerator
                     * (-base)^(2/3) is the same as ((-base)^2)^(1/3)
                     * any negative base squared is positive */
                    return Math.pow(-base, exponent);
                }

                /* return negative answer, make base and exponent positive */
                return -Math.pow(-base, exponent);
            }
        }

        return Math.pow(base, exponent);
    }

    /* Math function */
    private static double f(double x){
        /* example f(x) = x^(1/x) */
        return pow2(x, (double) 1/x);
    }

Выпуск № 1

Для обеих проблем я буду использовать математическую функцию $ f (x) = x ^ {\ frac {1} {x}} $ в качестве примера для графика, который демонстрирует обе проблемы - первая из них - FractionConversionException это вызвано наличием большого значения для показателя степени. Эта ошибка произойдет, если значение epsilon в моем коде будет изменено на 0.1, но, похоже, избежать ошибки при шаге epsilon 0.11. Я не уверен, как решить это правильно, но, глядя в класс Fraction, где он генерирует FractionConversionException, он использует условный оператор, который я мог бы скопировать в свою функцию pow2 () и заставить его вернуть NaN с кодом ниже. Но я не уверен, что это правильно!

        long overflow = Integer.MAX_VALUE;

        if (FastMath.abs(exponent) > overflow) {
            return Double.NaN;
        }

РЕДАКТИРОВАТЬ: Добавление оператора try / catch для создания экземпляра класса Fraction и возврата NaN в предложении catch представляется хорошим временным решением. Вместо приведенного выше кода.

Выпуск № 2

Построение математической функции $ f (x) = x ^ {\ frac {1} {x}} $ создает грязный участок слева, где $ x <0 $, см. Изображение ниже </p>

x^(1/x) plot

в отличие от того, как оно должно выглядеть

https://www.google.com/search?q=x^(1%2Fx)

Я не знаю, как избавиться от этого беспорядка, поэтому, где $ x <0 $, он должен быть неопределенным (NaN), в то же время позволяя функции pow2 () по-прежнему отображать такие функции, как $ x ^ {\ frac { 1} {3}} $, $ x ^ {\ frac {2} {3}} $, $ x ^ {x} $ и т. Д. * </p>

Я также не уверен, что установить maxDenominator при создании экземпляра объекта Fraction для хорошей производительности, не влияя при этом на результаты графика. Возможно, существует более быстрый алгоритм преобразования десятичной дроби в дробь, хотя я думаю, что Apache math3, вероятно, очень оптимизирован.

Edit: Выпуск 3 Я забыл рассмотреть иррациональные показатели, потому что я был слишком поглощен аккуратными фракциями. Мой алгоритм не работает для иррациональных показателей, таких как π, и строит две версии графа вместе. Из-за того, как класс Fraction округляет показатель степени, некоторые знаменатели считаются четными и нечетными. Возможно, при условии, что если иррациональный показатель не равен доле, вместо этого нужно вернуть NaN. Просто быстро протестировал это условие, пришлось добавить условие absoluteBase, которое переворачивает график в правильном направлении. Нужно сделать дальнейшее тестирование, но может быть идея.

Edit2: после тестирования он должен фактически вернуть обычную функцию pow () вместо NaN, чтобы обработать условия для иррациональных показателей (см. Обновленный код для модифицированной степенной функции), а также этому подходу неожиданно удается избавиться от большей части беспорядок, выделенный в выпуске № 2, так как я считаю, что в интервале больше иррациональных чисел, чем рациональных чисел, которые исключаются алгоритмом, что делает его менее плотным и труднее соединить две точки в линию, чтобы появиться на графике.


        if (exponent != fraction.doubleValue() && negativeBase){
            return Double.NaN;
        }

Дополнительный вопрос Является ли точным представление / представление этих данных функции, как это делают большинство современных графических программ (упомянутых выше), или это действительно вводит в заблуждение, учитывая, что обычная степенная функция рассматривает эти дополнительные данные для отрицательных базисов или показателей как неопределенные? И как эти регионы или части сюжета называются в математике (это технический термин)?

Также открыт для любого другого подхода или алгоритма

...