Графики функций JavaFX отличаются от графиков в Wolfram Alpha.

Я создал приложение-калькулятор, которое должно строить графики. Пользователь получает текстовое поле, в котором он может ввести формулу функции, которая затем проверяется и анализируется в ChartXY и так далее, чтобы нарисовать ее. В основном я использую для всех своих функций библиотеки из javafx .Я заметил, что мои результаты сильно отличаются. Большинство функций работают очень хорошо, но некоторые функции отличаются, как будто у меня есть реальная часть + мнимая часть, но у wolfram также добавлено зеркальное отражение. Пожалуйста, посмотрите на мои скриншоты.

Этот пример относится к log(x) домену (-6,6) кодовому домену (-2,2)

Сложный граф Wolfram Alpha: http://oi61.tinypic.com/2uij7l2.jpg

Скриншот моего приложения-калькулятора: http://oi62.tinypic.com/2m7xoi9.jpg

Другой пример: log(sin(x)) domain(-6.3,6.3) codomain (-7,2)

Настоящий Вольфрам: http://oi57.tinypic.com/2a5hoif.jpg

Комплекс вольфрама: http://oi59.tinypic.com/kesq49.jpg

Скриншот моего калькулятора: http://oi58.tinypic.com/2v13qpu.jpg

arctan(tan(x)) для домена(-6.3,6.3) кодомена(-2,2)

График Вольфрама: http://oi58.tinypic.com/hupze0.jpg

График моего приложения: http://oi62.tinypic.com/8wktmr.jpg

У меня такой вопрос: должно ли так быть, если нет, то почему так и можно ли это исправить?

Вот часть моего класса, которая содержит весь синтаксический анализ

public class Controller {

@FXML
private TextField domainTextField;
@FXML
private TextField codomainTextField;
@FXML
private LineChart coordinateLineChart;
@FXML
private TextField functionTextField;
@FXML
private NumberAxis xNumberAxis;
@FXML
private NumberAxis yNumberAxis;
@FXML
private ComboBox lineStyleComboBox;
@FXML
private ComboBox lineThiknessComboBox;
@FXML
private ColorPicker colorPicker;
@FXML
private Pane numericPane;
@FXML
private TextField descriptionTextField;
@FXML
private Label descriptionLabel;
@FXML
private VBox legendVBox;
@FXML
private CheckBox modificationModeCheckBox;
@FXML
private AnchorPane toSnapshot;

Stage stage;
MessageBox msgBox;
Intervals intervals = new Intervals();
LinkedList<FunctionViewHelper> functions = new LinkedList<FunctionViewHelper>();
boolean axisXdescriptionFlag = true;
boolean editingMode = false;
int editingFunctionId = 0;
int fontFactor = 0;
ObservableList<XYChart.Series> seriesListChart = FXCollections.observableArrayList();
ArrayList<XYChart.Series> lastSeries = new ArrayList<XYChart.Series>();
ArrayList<CustomFunction> exp4jCustomFunction = new ArrayList<CustomFunction>();

// Draws a graph
private void drawFormula(Calculable expression, ArrayList<String> conditions, String cssStyle) throws ScriptException {
    ArrayList<XYChart.Series> seriesList = new ArrayList<XYChart.Series>();
    seriesList.add(new XYChart.Series());
    double lastY = 0;
    for (double x = intervals.domainStart; x < intervals.domainEnd; x += 0.009) {
        if (Validator.ifAllConditionsTrue(conditions, x)) {
            if (x != intervals.domainStart) lastY = expression.calculate();
            expression.setVariable("x", x);
            if (Math.abs(lastY - expression.calculate()) > Const.brakeLineConst)
                seriesList.add(new XYChart.Series());
            seriesList.get(seriesList.size() - 1).getData().add(new XYChart.Data(x, expression.calculate()));
        }
    }

    seriesListChart.addAll(seriesList);
    lastSeries.addAll(seriesList);

    setSeriesStyle(seriesList, cssStyle);
}

// Parsing string to Calculable which we can draw.
    private Calculable buildExpression(String expression) throws UnparsableExpressionException, UnknownFunctionException {
        return new ExpressionBuilder(expression)
                .withVariableNames("x")
                .withCustomFunctions(exp4jCustomFunction)
                .build();
    }
 private void drawButtonHandler() {
        //TODO remove
        //domainTextFieldOnChange();
        Function function = null;
        if (!Validator.validateFofEmptyFields(domainTextField, functionTextField)) {
            msgBox.show("You have to specify domain and formula.");
            return;
        }
        if (!Validator.validateIntervals(intervals, codomainTextField)) {
            msgBox.show("Specify proper domain and codomain.");
            return;
        }
        try {
            if (!editingMode) {
                function = new Function(functionTextField.getText(), colorPicker.getValue(), (String) lineStyleComboBox.getValue(),
                        lineThiknessComboBox.getValue().toString());
                colorPicker.setValue(Const.getNextColor());
            } else {
                function = getByFunctionId(editingFunctionId).function;
                function.formula = functionTextField.getText();
                seriesListChart.removeAll(getByFunctionId(editingFunctionId).series);
            }
            ArrayList<String> conditions = new ArrayList<String>();
            drawFunctionReq(function.formula, conditions, function.getCss());
            if (!editingMode)
                functions.add(new FunctionViewHelper(function, addLegendFunctionView(function), new ArrayList<XYChart.Series>(lastSeries)));
            else {
                getByFunctionId(editingFunctionId).series = new ArrayList<XYChart.Series>(lastSeries);
                ((Label) getByFunctionId(editingFunctionId).view.getChildren().get(1)).setText(function.formula);
            }
        } catch (UnknownFunctionException ex) {
            ex.printStackTrace();
            msgBox.show("Unknown function.");
        } catch (UnparsableExpressionException ex) {
            ex.printStackTrace();
            msgBox.show("Unparsable expression.");
        } catch (Exception ex) {
            ex.printStackTrace();
            msgBox.show("Unknown error.");
        } finally {
            lastSeries.clear();
        }
    }
 @FXML
    private void domainTextFieldOnChange() {
        domainTextField.setStyle("");
        try {
            intervals.setDomain(domainTextField.getText());
            xNumberAxis.lowerBoundProperty().set(intervals.domainStart);
            xNumberAxis.upperBoundProperty().set(intervals.domainEnd);
        } catch (Exception e) {
            domainTextField.setStyle("-fx-focus-color: red;");
            e.printStackTrace();
        }
    }

    @FXML
    private void codomainTextFieldOnChange() {
        codomainTextField.setStyle("");
        if (!codomainTextField.getText().isEmpty()) {
            try {
                intervals.setCodomain(codomainTextField.getText());

                yNumberAxis.setAutoRanging(false);
                yNumberAxis.setUpperBound(intervals.codomainEnd);
                yNumberAxis.setLowerBound(intervals.codomainStart);
            } catch (Exception e) {
                codomainTextField.setStyle("-fx-focus-color: red;");
                e.printStackTrace();
            }
        } else yNumberAxis.setAutoRanging(true);
    }

person user61139    schedule 14.02.2015    source источник
comment
Какой у Вас вопрос?   -  person jewelsea    schedule 14.02.2015
comment
Извините, что поздно... Сейчас исправлено.   -  person user61139    schedule 14.02.2015


Ответы (1)


ВА правильно. В мнимой составляющей, которой является arg(z), должен быть скачок от pi к 0 при z=0. Реальный компонент — log(|z|).

Угадайте на ровном месте: обязательно используйте arctan2 при вычислении углов.

person Lutz Lehmann    schedule 14.02.2015
comment
Спасибо за ваш ответ. Я добавил код синтаксического анализа из своего приложения. Я действительно не понимаю, как я могу это исправить, потому что похоже, что проблема в библиотеке. Не могли бы вы сказать мне, можно ли это исправить после изучения кода ? - person user61139; 14.02.2015
comment
Вы уверены, что ваш оценщик выражений использует функции над комплексными числами? Кажется, что для отрицательного x вы ничего не получаете. - person Lutz Lehmann; 14.02.2015
comment
Сначала я был уверен, что нет, но теперь я действительно запутался, особенно потому, что там появляется эта функция прямоугольной формы (которая, насколько я знаю, не является реальной частью). - person user61139; 14.02.2015
comment
Это может быть связано с особенностью логарифма. Если значение по умолчанию для ничего очень велико и поскольку log(0,009) очень велико в отрицательном направлении, вы получите вертикальную линию на нуле. Просто напечатайте значения в списке значений. Или используйте больший диапазон, например, -10..10. - person Lutz Lehmann; 14.02.2015
comment
Как насчет случая log(sin(x))? - person user61139; 14.02.2015
comment
У этого те же проблемы. Действительный логарифм не определен для отрицательных аргументов, возвращаемое значение должно быть NaN, но я не уверен, поддерживает ли Java это двойное значение. - person Lutz Lehmann; 14.02.2015
comment
Я проверил значения Nan, и это оказалось проблемой. Библиотека сохраняла значения Nan в список, а затем пыталась его нарисовать. Я добавил if(!Double.isNaN(expression.calculate())) перед рисованием, и теперь это хорошо, хотя и не решило проблему в более сложных функциях. - person user61139; 15.02.2015
comment
Если сложная арифметика недоступна, компоненты log(x+i*y) вычисляются как 0.5*log(x*x+y*y) и atan2(y,x), в вашем случае оба в y=0, для несингулярных графиков используйте y=1e-6 или что-то подобное маленькое. - person Lutz Lehmann; 15.02.2015