File indexing completed on 2024-05-19 05:51:35
0001 /* 0002 * SPDX-FileCopyrightText: 2023 Michael Lang <criticaltemp@protonmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-3.0-or-later 0005 */ 0006 0007 #include "qalculateengine.h" 0008 #include "kalkconfig.h" 0009 0010 #include <libqalculate/Calculator.h> 0011 0012 #include <QLocale> 0013 0014 #include <KLocalizedString> 0015 0016 constexpr std::array<QStringView, 6> ANGLE_UNITS = {u"Radians", u"Degrees", u"Gradians", u"Arcminute", u"Arcsecond", u"Turn"}; 0017 constexpr std::array<ParsingMode, 5> PARSING_MODES = {PARSING_MODE_ADAPTIVE, 0018 PARSING_MODE_CONVENTIONAL, 0019 PARSING_MODE_IMPLICIT_MULTIPLICATION_FIRST, 0020 PARSING_MODE_CHAIN, 0021 PARSING_MODE_RPN}; 0022 0023 QalculateEngine::QalculateEngine() 0024 { 0025 new Calculator(); 0026 CALCULATOR->terminateThreads(); 0027 CALCULATOR->loadGlobalDefinitions(); 0028 CALCULATOR->loadLocalDefinitions(); 0029 CALCULATOR->loadGlobalCurrencies(); 0030 CALCULATOR->loadExchangeRates(); 0031 CALCULATOR->loadGlobalPrefixes(); 0032 CALCULATOR->loadGlobalUnits(); 0033 CALCULATOR->loadGlobalDataSets(); 0034 } 0035 0036 QalculateEngine *QalculateEngine::inst() 0037 { 0038 static QalculateEngine singleton; 0039 return &singleton; 0040 } 0041 0042 QString QalculateEngine::evaluate(QString &expression, bool *isApproximate, const int baseEval, const int basePrint, bool exact, const int minExp) 0043 { 0044 CALCULATOR->abort(); 0045 0046 if (QStringLiteral("+−-×÷/^").contains(expression.right(1))) { 0047 expression.truncate(expression.size() - 1); 0048 } 0049 0050 // do not need to evalulate if the expression is just a number or if expression is incomplete 0051 if (baseEval == 10 && expression.toDouble() != 0 && !expression.contains(QStringLiteral("E"), Qt::CaseInsensitive)) { 0052 m_result = QString(); 0053 return m_result; 0054 } else if (QStringLiteral("(√∛").contains(expression.right(1))) { 0055 m_result = QString(); 0056 return m_result; 0057 } 0058 0059 expression.replace(HAIR_SPACE.toString(), QStringLiteral(" + ")); 0060 expression.replace(QStringLiteral("%%"), QStringLiteral("percentpercent")); 0061 0062 const bool showAprox = expression.contains(QStringLiteral("∫")) || expression.contains(QStringLiteral("integra"), Qt::CaseInsensitive); 0063 0064 EvaluationOptions eo; 0065 eo.auto_post_conversion = POST_CONVERSION_BEST; 0066 eo.keep_zero_units = false; 0067 eo.structuring = STRUCTURING_SIMPLIFY; 0068 eo.mixed_units_conversion = MIXED_UNITS_CONVERSION_NONE; 0069 eo.approximation = exact ? APPROXIMATION_EXACT : APPROXIMATION_TRY_EXACT; 0070 eo.parse_options.base = baseEval; 0071 eo.parse_options.parsing_mode = PARSING_MODES.at(KalkConfig::self()->parsingMode()); 0072 eo.parse_options.angle_unit = ANGLE_UNIT_CUSTOM; 0073 eo.parse_options.limit_implicit_multiplication = false; 0074 eo.parse_options.unknowns_enabled = false; 0075 0076 PrintOptions po; 0077 po.base = basePrint; 0078 po.number_fraction_format = exact ? FRACTION_COMBINED : FRACTION_DECIMAL; 0079 po.indicate_infinite_series = false; 0080 po.base_display = BASE_DISPLAY_NORMAL; 0081 po.interval_display = expression.contains(QStringLiteral("+/-")) ? INTERVAL_DISPLAY_PLUSMINUS : INTERVAL_DISPLAY_SIGNIFICANT_DIGITS; 0082 po.is_approximate = isApproximate; 0083 po.use_unicode_signs = true; 0084 po.binary_bits = baseEval == 2 ? std::max(std::ceil(expression.size() / 4.0) * 4.0, 4.0) : 0; 0085 po.preserve_precision = false; 0086 po.min_exp = minExp; 0087 po.multiplication_sign = MULTIPLICATION_SIGN_X; 0088 po.division_sign = DIVISION_SIGN_DIVISION_SLASH; 0089 po.improve_division_multipliers = showAprox; 0090 po.preserve_format = false; 0091 po.restrict_to_parent_precision = true; 0092 0093 CALCULATOR->setCustomAngleUnit(CALCULATOR->getActiveUnit(ANGLE_UNITS.at(KalkConfig::self()->angleUnit()).toUtf8().constData())); 0094 CALCULATOR->setPrecision(KalkConfig::self()->precision()); 0095 0096 std::string input = CALCULATOR->unlocalizeExpression(expression.toStdString(), eo.parse_options); 0097 std::string parsed; 0098 std::string result; 0099 AutomaticFractionFormat fracFormat = exact ? AUTOMATIC_FRACTION_OFF : AUTOMATIC_FRACTION_SINGLE; 0100 AutomaticApproximation autoAprox = showAprox ? AUTOMATIC_APPROXIMATION_AUTO : AUTOMATIC_APPROXIMATION_SINGLE; 0101 bool is_comparison = false; 0102 result = CALCULATOR->calculateAndPrint(input, 2000, eo, po, fracFormat, autoAprox, &parsed, -1, &is_comparison, false); 0103 m_result = QString::fromStdString(result); 0104 qDebug() << QString::fromStdString(parsed) << (*isApproximate ? "≈" : "=") << m_result; 0105 0106 while (CALCULATOR->message()) { 0107 MessageType mtype = CALCULATOR->message()->type(); 0108 if (mtype != MESSAGE_INFORMATION) { 0109 QStringView type = mtype == MESSAGE_WARNING ? i18n("warning") : i18n("error"); 0110 qDebug() << type + QStringLiteral(": ") + QString::fromStdString(CALCULATOR->message()->message()); 0111 } 0112 CALCULATOR->nextMessage(); 0113 } 0114 0115 if (exact && m_result.contains(QStringLiteral(" ∕ "))) { 0116 m_result.replace(QStringLiteral(" ∕ "), FRACTION_SLASH.toString()); 0117 m_result.replace(QStringLiteral(" + "), HAIR_SPACE.toString()); 0118 } 0119 0120 m_result.replace(QLatin1Char('.'), QLocale().decimalPoint(), Qt::CaseInsensitive); 0121 0122 return m_result; 0123 } 0124 0125 #include "moc_qalculateengine.cpp"