diff --git a/kcalc.cpp b/kcalc.cpp index 0f11b5c..2c7c330 100644 --- a/kcalc.cpp +++ b/kcalc.cpp @@ -1,2335 +1,2335 @@ /* Copyright (C) 2001 - 2013 Evan Teran evan.teran@gmail.com Copyright (C) 2006 Michel Marti mma@objectxp.com Copyright (C) 1996 - 2000 Bernd Johannes Wuebben wuebben@kde.org This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "kcalc_version.h" #include "kcalc.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kcalc_bitset.h" #include "kcalc_const_menu.h" #include "kcalc_settings.h" #include "kcalc_statusbar.h" #include "kcalcdisplay.h" namespace { const char description[] = I18N_NOOP("KDE Calculator"); const int maxprecision = 1000; } //------------------------------------------------------------------------------ // Name: KCalculator // Desc: constructor //------------------------------------------------------------------------------ KCalculator::KCalculator(QWidget *parent) : KXmlGuiWindow(parent), shift_mode_(false), hyp_mode_(false), memory_num_(0.0), constants_menu_(nullptr), constants_(nullptr), core() { // central widget to contain all the elements QWidget *const central = new QWidget(this); central->setLayoutDirection(Qt::LeftToRight); setCentralWidget(central); KAcceleratorManager::setNoAccel(central); // load science constants_ from xml-file KCalcConstMenu::init_consts(); // setup interface (order is critical) setupUi(central); setupMainActions(); setStatusBar(new KCalcStatusBar(this)); createGUI(); setupKeys(); toolBar()->hide(); // hide by default // create button groups base_choose_group_ = new QButtonGroup(this); base_choose_group_->setExclusive(true); base_choose_group_->addButton(hexRadio, HexMode); base_choose_group_->addButton(decRadio, DecMode); base_choose_group_->addButton(octRadio, OctMode); base_choose_group_->addButton(binRadio, BinMode); connect(base_choose_group_, static_cast(&QButtonGroup::buttonClicked), this, &KCalculator::slotBaseSelected); angle_choose_group_ = new QButtonGroup(this); angle_choose_group_->setExclusive(true); angle_choose_group_->addButton(degRadio, DegMode); angle_choose_group_->addButton(radRadio, RadMode); angle_choose_group_->addButton(gradRadio, GradMode); connect(angle_choose_group_, static_cast(&QButtonGroup::buttonClicked), this, &KCalculator::slotAngleSelected); // additional menu setup constants_menu_ = createConstantsMenu(); menuBar()->insertMenu((menuBar()->actions)()[2], constants_menu_); // misc setup setColors(); setFonts(); // Show the result in the app's caption in taskbar (wishlist - bug #52858) if (KCalcSettings::captionResult() == true) { connect(calc_display, &KCalcDisplay::changedText, this, &KCalculator::setWindowTitle); } calc_display->changeSettings(); setPrecision(); updateGeometry(); layout()->setSizeConstraint(QLayout::SetFixedSize); updateDisplay(UPDATE_FROM_CORE); // misc settings KCalcSettings::EnumCalculatorMode::type calculatorMode = KCalcSettings::calculatorMode(); switch (calculatorMode) { case KCalcSettings::EnumCalculatorMode::science: action_mode_science_->setChecked(true); break; case KCalcSettings::EnumCalculatorMode::statistics: action_mode_statistic_->setChecked(true); break; case KCalcSettings::EnumCalculatorMode::numeral: action_mode_numeral_->setChecked(true); break; case KCalcSettings::EnumCalculatorMode::simple: default: action_mode_simple_->setChecked(true); } setAngle(); setBase(); calc_display->setFocus(); } //------------------------------------------------------------------------------ // Name: ~KCalculator // Desc: deconstructor //------------------------------------------------------------------------------ KCalculator::~KCalculator() { KCalcSettings::self()->save(); } //------------------------------------------------------------------------------ // Name: setupMainActions // Desc: connects all of the basic actions //------------------------------------------------------------------------------ void KCalculator::setupMainActions() { // file menu KStandardAction::quit(this, SLOT(close()), actionCollection()); // edit menu KStandardAction::undo(calc_display, SLOT(slotHistoryBack()), actionCollection()); KStandardAction::redo(calc_display, SLOT(slotHistoryForward()), actionCollection()); KStandardAction::cut(calc_display, SLOT(slotCut()), actionCollection()); KStandardAction::copy(calc_display, SLOT(slotCopy()), actionCollection()); KStandardAction::paste(calc_display, SLOT(slotPaste()), actionCollection()); // mode menu QActionGroup *modeGroup = new QActionGroup(this); action_mode_simple_ = actionCollection()->add(QLatin1String("mode_simple")); action_mode_simple_->setActionGroup(modeGroup); action_mode_simple_->setText(i18n("Simple Mode")); connect(action_mode_simple_, &KToggleAction::toggled, this, &KCalculator::slotSetSimpleMode); action_mode_science_ = actionCollection()->add(QLatin1String("mode_science")); action_mode_science_->setActionGroup(modeGroup); action_mode_science_->setText(i18n("Science Mode")); connect(action_mode_science_, &KToggleAction::toggled, this, &KCalculator::slotSetScienceMode); action_mode_statistic_ = actionCollection()->add(QLatin1String("mode_statistics")); action_mode_statistic_->setActionGroup(modeGroup); action_mode_statistic_->setText(i18n("Statistic Mode")); connect(action_mode_statistic_, &KToggleAction::toggled, this, &KCalculator::slotSetStatisticMode); action_mode_numeral_ = actionCollection()->add(QLatin1String("mode_numeral")); action_mode_numeral_->setActionGroup(modeGroup); action_mode_numeral_->setText(i18n("Numeral System Mode")); connect(action_mode_numeral_, &KToggleAction::toggled, this, &KCalculator::slotSetNumeralMode); // settings menu action_constants_show_ = actionCollection()->add(QLatin1String("show_constants")); action_constants_show_->setText(i18n("Constants &Buttons")); action_constants_show_->setChecked(true); connect(action_constants_show_, &KToggleAction::toggled, this, &KCalculator::slotConstantsShow); action_bitset_show_ = actionCollection()->add(QLatin1String("show_bitset")); action_bitset_show_->setText(i18n("Show B&it Edit")); action_bitset_show_->setChecked(true); connect(action_bitset_show_, &KToggleAction::toggled, this, &KCalculator::slotBitsetshow); KStandardAction::preferences(this, SLOT(showSettings()), actionCollection()); KStandardAction::keyBindings(guiFactory(), SLOT(configureShortcuts()), actionCollection()); } //------------------------------------------------------------------------------ // Name: createConstantsMenu // Desc: creates and returns a pointer to the constant menu //------------------------------------------------------------------------------ KCalcConstMenu *KCalculator::createConstantsMenu() { KCalcConstMenu *const menu = new KCalcConstMenu(i18n("&Constants"), this); connect(menu, &KCalcConstMenu::triggeredConstant, this, &KCalculator::slotConstantToDisplay); return menu; } //------------------------------------------------------------------------------ // Name: statusBar // Desc: returns a pointer to the status bar //------------------------------------------------------------------------------ KCalcStatusBar *KCalculator::statusBar() { return static_cast(KXmlGuiWindow::statusBar()); } //------------------------------------------------------------------------------ // Name: setupNumberKeys // Desc: sets up number keys and related shortcuts //------------------------------------------------------------------------------ void KCalculator::setupNumberKeys() { num_button_group_ = new QButtonGroup(this); connect(num_button_group_, static_cast(&QButtonGroup::buttonClicked), this, &KCalculator::slotNumberclicked); num_button_group_->addButton(pb0, 0); num_button_group_->addButton(pb1, 1); num_button_group_->addButton(pb2, 2); num_button_group_->addButton(pb3, 3); num_button_group_->addButton(pb4, 4); num_button_group_->addButton(pb5, 5); num_button_group_->addButton(pb6, 6); num_button_group_->addButton(pb7, 7); num_button_group_->addButton(pb8, 8); num_button_group_->addButton(pb9, 9); num_button_group_->addButton(pbA, 0xA); num_button_group_->addButton(pbB, 0xB); num_button_group_->addButton(pbC, 0xC); num_button_group_->addButton(pbD, 0xD); num_button_group_->addButton(pbE, 0xE); num_button_group_->addButton(pbF, 0xF); connect(this, &KCalculator::switchShowAccels, pb0, &KCalcButton::slotSetAccelDisplayMode); connect(this, &KCalculator::switchShowAccels, pb1, &KCalcButton::slotSetAccelDisplayMode); connect(this, &KCalculator::switchShowAccels, pb2, &KCalcButton::slotSetAccelDisplayMode); connect(this, &KCalculator::switchShowAccels, pb3, &KCalcButton::slotSetAccelDisplayMode); connect(this, &KCalculator::switchShowAccels, pb4, &KCalcButton::slotSetAccelDisplayMode); connect(this, &KCalculator::switchShowAccels, pb5, &KCalcButton::slotSetAccelDisplayMode); connect(this, &KCalculator::switchShowAccels, pb6, &KCalcButton::slotSetAccelDisplayMode); connect(this, &KCalculator::switchShowAccels, pb7, &KCalcButton::slotSetAccelDisplayMode); connect(this, &KCalculator::switchShowAccels, pb8, &KCalcButton::slotSetAccelDisplayMode); connect(this, &KCalculator::switchShowAccels, pb9, &KCalcButton::slotSetAccelDisplayMode); connect(this, &KCalculator::switchShowAccels, pbA, &KCalcButton::slotSetAccelDisplayMode); connect(this, &KCalculator::switchShowAccels, pbB, &KCalcButton::slotSetAccelDisplayMode); connect(this, &KCalculator::switchShowAccels, pbC, &KCalcButton::slotSetAccelDisplayMode); connect(this, &KCalculator::switchShowAccels, pbD, &KCalcButton::slotSetAccelDisplayMode); connect(this, &KCalculator::switchShowAccels, pbE, &KCalcButton::slotSetAccelDisplayMode); connect(this, &KCalculator::switchShowAccels, pbF, &KCalcButton::slotSetAccelDisplayMode); } //------------------------------------------------------------------------------ // Name: setupRightKeypad // Desc: sets up right keypad keys and related shortcuts //------------------------------------------------------------------------------ void KCalculator::setupRightKeypad() { connect(pbShift, &KCalcButton::toggled, this, &KCalculator::slotShifttoggled); connect(this, &KCalculator::switchShowAccels, pbShift, &KCalcButton::slotSetAccelDisplayMode); pbBackspace->setShortcut(QKeySequence(Qt::Key_Backspace)); new QShortcut(Qt::Key_PageUp, pbBackspace, SLOT(animateClick())); connect(pbBackspace, &KCalcButton::clicked, this, &KCalculator::slotBackspaceclicked); connect(this, &KCalculator::switchShowAccels, pbBackspace, &KCalcButton::slotSetAccelDisplayMode); pbClear->setShortcut(QKeySequence(Qt::Key_Escape)); new QShortcut(Qt::Key_PageUp, pbClear, SLOT(animateClick())); connect(pbClear, &KCalcButton::clicked, this, &KCalculator::slotClearclicked); connect(this, &KCalculator::switchShowAccels, pbClear, &KCalcButton::slotSetAccelDisplayMode); pbAllClear->setShortcut(QKeySequence(Qt::Key_Delete)); new QShortcut(Qt::Key_PageDown, pbAllClear, SLOT(animateClick())); connect(pbAllClear, &KCalcButton::clicked, this, &KCalculator::slotAllClearclicked); connect(this, &KCalculator::switchShowAccels, pbAllClear, &KCalcButton::slotSetAccelDisplayMode); pbParenOpen->setShortcut(QKeySequence(Qt::Key_ParenLeft)); connect(pbParenOpen, &KCalcButton::clicked, this, &KCalculator::slotParenOpenclicked); connect(this, &KCalculator::switchShowAccels, pbParenOpen, &KCalcButton::slotSetAccelDisplayMode); pbParenClose->setShortcut(QKeySequence(Qt::Key_ParenRight)); connect(pbParenClose, &KCalcButton::clicked, this, &KCalculator::slotParenCloseclicked); connect(this, &KCalculator::switchShowAccels, pbParenClose, &KCalcButton::slotSetAccelDisplayMode); pbMemRecall->setDisabled(true); // nothing in memory at start connect(pbMemRecall, &KCalcButton::clicked, this, &KCalculator::slotMemRecallclicked); connect(this, &KCalculator::switchShowAccels, pbMemRecall, &KCalcButton::slotSetAccelDisplayMode); connect(pbMemClear, &KCalcButton::clicked, this, &KCalculator::slotMemClearclicked); connect(this, &KCalculator::switchShowAccels, pbMemClear, &KCalcButton::slotSetAccelDisplayMode); pbMemPlusMinus->addMode(ModeNormal, i18nc("Add display to memory", "M+"), i18n("Add display to memory")); pbMemPlusMinus->addMode(ModeShift, i18nc("Subtract from memory", "M\xe2\x88\x92"), i18n("Subtract from memory")); connect(pbMemPlusMinus, &KCalcButton::clicked, this, &KCalculator::slotMemPlusMinusclicked); connect(this, &KCalculator::switchShowAccels, pbMemPlusMinus, &KCalcButton::slotSetAccelDisplayMode); connect(this, &KCalculator::switchMode, pbMemPlusMinus, &KCalcButton::slotSetMode); connect(pbMemStore, &KCalcButton::clicked, this, &KCalculator::slotMemStoreclicked); connect(this, &KCalculator::switchShowAccels, pbMemStore, &KCalcButton::slotSetAccelDisplayMode); pbPercent->setShortcut(QKeySequence(Qt::Key_Percent)); connect(pbPercent, &KCalcButton::clicked, this, &KCalculator::slotPercentclicked); connect(this, &KCalculator::switchShowAccels, pbPercent, &KCalcButton::slotSetAccelDisplayMode); pbPlusMinus->setShortcut(QKeySequence(Qt::Key_Backslash)); connect(pbPlusMinus, &KCalcButton::clicked, this, &KCalculator::slotPlusMinusclicked); connect(this, &KCalculator::switchShowAccels, pbPlusMinus, &KCalcButton::slotSetAccelDisplayMode); } //------------------------------------------------------------------------------ // Name: setupNumericKeypad // Desc: sets up numeric keys and related shortcuts //------------------------------------------------------------------------------ void KCalculator::setupNumericKeypad() { pbCube->addMode(ModeNormal, i18nc("Third power", "x3"), i18n("Third power")); pbCube->addMode(ModeShift, QLatin1String("3√x"), i18n("Cube root")); connect(pbCube, &KCalcButton::clicked, this, &KCalculator::slotCubeclicked); connect(this, &KCalculator::switchShowAccels, pbCube, &KCalcButton::slotSetAccelDisplayMode); connect(this, &KCalculator::switchMode, pbCube, &KCalcButton::slotSetMode); pbDivision->setShortcut(QKeySequence(Qt::Key_Slash)); new QShortcut(Qt::Key_division, pbDivision, SLOT(animateClick())); connect(pbDivision, &KCalcButton::clicked, this, &KCalculator::slotDivisionclicked); connect(this, &KCalculator::switchShowAccels, pbDivision, &KCalcButton::slotSetAccelDisplayMode); pbMultiplication->setShortcut(QKeySequence(Qt::Key_Asterisk)); new QShortcut(Qt::Key_X, pbMultiplication, SLOT(animateClick())); new QShortcut(Qt::Key_multiply, pbMultiplication, SLOT(animateClick())); connect(pbMultiplication, &KCalcButton::clicked, this, &KCalculator::slotMultiplicationclicked); connect(this, &KCalculator::switchShowAccels, pbMultiplication, &KCalcButton::slotSetAccelDisplayMode); pbMinus->setShortcut(QKeySequence(Qt::Key_Minus)); connect(pbMinus, &KCalcButton::clicked, this, &KCalculator::slotMinusclicked); connect(this, &KCalculator::switchShowAccels, pbMinus, &KCalcButton::slotSetAccelDisplayMode); pbPlus->setShortcut(QKeySequence(Qt::Key_Plus)); connect(pbPlus, &KCalcButton::clicked, this, &KCalculator::slotPlusclicked); connect(this, &KCalculator::switchShowAccels, pbPlus, &KCalcButton::slotSetAccelDisplayMode); // set decimal separator from locale pbPeriod->setText(QString(QLocale().decimalPoint())); pbPeriod->setShortcut(QString(QLocale().decimalPoint())); // add shortcut for the other decimal separator (point or comma) if (QLocale().decimalPoint() == QLatin1Char('.')) { new QShortcut(Qt::Key_Comma, pbPeriod, SLOT(animateClick())); } else if (QLocale().decimalPoint() == QLatin1Char(',')) { new QShortcut(Qt::Key_Period, pbPeriod, SLOT(animateClick())); } connect(pbPeriod, &KCalcButton::clicked, this, &KCalculator::slotPeriodclicked); connect(this, &KCalculator::switchShowAccels, pbPeriod, &KCalcButton::slotSetAccelDisplayMode); pbEqual->setShortcut(QKeySequence(Qt::Key_Enter)); new QShortcut(Qt::Key_Equal, pbEqual, SLOT(animateClick())); new QShortcut(Qt::Key_Return, pbEqual, SLOT(animateClick())); connect(pbEqual, &KCalcButton::clicked, this, &KCalculator::slotEqualclicked); connect(this, &KCalculator::switchShowAccels, pbEqual, &KCalcButton::slotSetAccelDisplayMode); } //------------------------------------------------------------------------------ // Name: setupLogicKeys // Desc: sets up logic keys and related shortcuts //------------------------------------------------------------------------------ void KCalculator::setupLogicKeys() { logic_buttons_.append(pbAND); logic_buttons_.append(pbOR); logic_buttons_.append(pbXOR); logic_buttons_.append(pbLsh); logic_buttons_.append(pbRsh); logic_buttons_.append(pbCmp); pbAND->setShortcut(QKeySequence(Qt::Key_Ampersand)); connect(this, &KCalculator::switchShowAccels, pbAND, &KCalcButton::slotSetAccelDisplayMode); connect(pbAND, &KCalcButton::clicked, this, &KCalculator::slotANDclicked); pbOR->setShortcut(QKeySequence(Qt::Key_Bar)); connect(this, &KCalculator::switchShowAccels, pbOR, &KCalcButton::slotSetAccelDisplayMode); connect(pbOR, &KCalcButton::clicked, this, &KCalculator::slotORclicked); connect(this, &KCalculator::switchShowAccels, pbXOR, &KCalcButton::slotSetAccelDisplayMode); connect(pbXOR, &KCalcButton::clicked, this, &KCalculator::slotXORclicked); pbLsh->setShortcut(QKeySequence(Qt::Key_Less)); connect(this, &KCalculator::switchShowAccels, pbLsh, &KCalcButton::slotSetAccelDisplayMode); connect(pbLsh, &KCalcButton::clicked, this, &KCalculator::slotLeftShiftclicked); pbRsh->setShortcut(QKeySequence(Qt::Key_Greater)); connect(this, &KCalculator::switchShowAccels, pbRsh, &KCalcButton::slotSetAccelDisplayMode); connect(pbRsh, &KCalcButton::clicked, this, &KCalculator::slotRightShiftclicked); pbCmp->setShortcut(QKeySequence(Qt::Key_AsciiTilde)); connect(this, &KCalculator::switchShowAccels, pbCmp, &KCalcButton::slotSetAccelDisplayMode); connect(pbCmp, &KCalcButton::clicked, this, &KCalculator::slotNegateclicked); } //------------------------------------------------------------------------------ // Name: setupLogicKeys // Desc: sets up scientific keys and related shortcuts //------------------------------------------------------------------------------ void KCalculator::setupScientificKeys() { scientific_buttons_.append(pbHyp); scientific_buttons_.append(pbSin); scientific_buttons_.append(pbCos); scientific_buttons_.append(pbTan); scientific_buttons_.append(pbLog); scientific_buttons_.append(pbLn); connect(this, &KCalculator::switchShowAccels, pbHyp, &KCalcButton::slotSetAccelDisplayMode); connect(pbHyp, &KCalcButton::toggled, this, &KCalculator::slotHyptoggled); pbSin->addMode(ModeNormal, i18nc("Sine", "Sin"), i18n("Sine")); pbSin->addMode(ModeShift, i18nc("Arc sine", "Asin"), i18n("Arc sine")); pbSin->addMode(ModeHyperbolic, i18nc("Hyperbolic sine", "Sinh"), i18n("Hyperbolic sine")); pbSin->addMode(ButtonModeFlags(ModeShift | ModeHyperbolic), i18nc("Inverse hyperbolic sine", "Asinh"), i18n("Inverse hyperbolic sine")); connect(this, &KCalculator::switchShowAccels, pbSin, &KCalcButton::slotSetAccelDisplayMode); connect(this, &KCalculator::switchMode, pbSin, &KCalcButton::slotSetMode); connect(pbSin, &KCalcButton::clicked, this, &KCalculator::slotSinclicked); pbCos->addMode(ModeNormal, i18nc("Cosine", "Cos"), i18n("Cosine")); pbCos->addMode(ModeShift, i18nc("Arc cosine", "Acos"), i18n("Arc cosine")); pbCos->addMode(ModeHyperbolic, i18nc("Hyperbolic cosine", "Cosh"), i18n("Hyperbolic cosine")); pbCos->addMode(ButtonModeFlags(ModeShift | ModeHyperbolic), i18nc("Inverse hyperbolic cosine", "Acosh"), i18n("Inverse hyperbolic cosine")); connect(this, &KCalculator::switchShowAccels, pbCos, &KCalcButton::slotSetAccelDisplayMode); connect(this, &KCalculator::switchMode, pbCos, &KCalcButton::slotSetMode); connect(pbCos, &KCalcButton::clicked, this, &KCalculator::slotCosclicked); pbTan->addMode(ModeNormal, i18nc("Tangent", "Tan"), i18n("Tangent")); pbTan->addMode(ModeShift, i18nc("Arc tangent", "Atan"), i18n("Arc tangent")); pbTan->addMode(ModeHyperbolic, i18nc("Hyperbolic tangent", "Tanh"), i18n("Hyperbolic tangent")); pbTan->addMode(ButtonModeFlags(ModeShift | ModeHyperbolic), i18nc("Inverse hyperbolic tangent", "Atanh"), i18n("Inverse hyperbolic tangent")); connect(this, &KCalculator::switchShowAccels, pbTan, &KCalcButton::slotSetAccelDisplayMode); connect(this, &KCalculator::switchMode, pbTan, &KCalcButton::slotSetMode); connect(pbTan, &KCalcButton::clicked, this, &KCalculator::slotTanclicked); pbLog->addMode(ModeNormal, i18nc("Logarithm to base 10", "Log"), i18n("Logarithm to base 10")); pbLog->addMode(ModeShift, i18nc("10 to the power of x", "10x"), i18n("10 to the power of x")); connect(this, &KCalculator::switchShowAccels, pbLog, &KCalcButton::slotSetAccelDisplayMode); connect(this, &KCalculator::switchMode, pbLog, &KCalcButton::slotSetMode); connect(pbLog, &KCalcButton::clicked, this, &KCalculator::slotLogclicked); pbLn->addMode(ModeNormal, i18nc("Natural log", "Ln"), i18n("Natural log")); pbLn->addMode(ModeShift, i18nc("Exponential function", "ex"), i18n("Exponential function")); connect(this, &KCalculator::switchShowAccels, pbLn, &KCalcButton::slotSetAccelDisplayMode); connect(this, &KCalculator::switchMode, pbLn, &KCalcButton::slotSetMode); connect(pbLn, &KCalcButton::clicked, this, &KCalculator::slotLnclicked); } //------------------------------------------------------------------------------ // Name: setupStatisticKeys // Desc: sets up statistical keys and related shortcuts //------------------------------------------------------------------------------ void KCalculator::setupStatisticKeys() { stat_buttons_.append(pbNData); stat_buttons_.append(pbMean); stat_buttons_.append(pbSd); stat_buttons_.append(pbMed); stat_buttons_.append(pbDat); stat_buttons_.append(pbCSt); pbNData->addMode(ModeNormal, i18nc("Number of data entered", "N"), i18n("Number of data entered")); pbNData->addMode(ModeShift, QString::fromUtf8("\xce\xa3") + QLatin1Char('x'), i18n("Sum of all data items")); connect(this, &KCalculator::switchShowAccels, pbNData, &KCalcButton::slotSetAccelDisplayMode); connect(this, &KCalculator::switchMode, pbNData, &KCalcButton::slotSetMode); connect(pbNData, &KCalcButton::clicked, this, &KCalculator::slotStatNumclicked); pbMean->addMode(ModeNormal, i18nc("Mean", "Mea"), i18n("Mean")); pbMean->addMode(ModeShift, QString::fromUtf8("\xce\xa3") + QLatin1String("x2"), i18n("Sum of all data items squared")); connect(this, &KCalculator::switchShowAccels, pbMean, &KCalcButton::slotSetAccelDisplayMode); connect(this, &KCalculator::switchMode, pbMean, &KCalcButton::slotSetMode); connect(pbMean, &KCalcButton::clicked, this, &KCalculator::slotStatMeanclicked); pbSd->addMode(ModeNormal, QString::fromUtf8("\xcf\x83") + QLatin1String("N"), i18n("Standard deviation")); pbSd->addMode(ModeShift, QString::fromUtf8("\xcf\x83") + QLatin1String("N-1"), i18n("Sample standard deviation")); connect(this, &KCalculator::switchShowAccels, pbSd, &KCalcButton::slotSetAccelDisplayMode); connect(this, &KCalculator::switchMode, pbSd, &KCalcButton::slotSetMode); connect(pbSd, &KCalcButton::clicked, this, &KCalculator::slotStatStdDevclicked); connect(this, &KCalculator::switchShowAccels, pbMed, &KCalcButton::slotSetAccelDisplayMode); connect(pbMed, &KCalcButton::clicked, this, &KCalculator::slotStatMedianclicked); pbDat->addMode(ModeNormal, i18nc("Enter data", "Dat"), i18n("Enter data")); pbDat->addMode(ModeShift, i18nc("Delete last data item", "CDat"), i18n("Delete last data item")); connect(this, &KCalculator::switchShowAccels, pbDat, &KCalcButton::slotSetAccelDisplayMode); connect(this, &KCalculator::switchMode, pbDat, &KCalcButton::slotSetMode); connect(pbDat, &KCalcButton::clicked, this, &KCalculator::slotStatDataInputclicked); connect(this, &KCalculator::switchShowAccels, pbCSt, &KCalcButton::slotSetAccelDisplayMode); connect(pbCSt, &KCalcButton::clicked, this, &KCalculator::slotStatClearDataclicked); } //------------------------------------------------------------------------------ // Name: setupConstantsKeys // Desc: sets up constants keys and related shortcuts //------------------------------------------------------------------------------ void KCalculator::setupConstantsKeys() { const_buttons_.append(pbC1); const_buttons_.append(pbC2); const_buttons_.append(pbC3); const_buttons_.append(pbC4); const_buttons_.append(pbC5); const_buttons_.append(pbC6); pbC1->setButtonNumber(0); connect(this, &KCalculator::switchShowAccels, pbC1, &KCalcConstButton::slotSetAccelDisplayMode); connect(this, &KCalculator::switchMode, pbC1, &KCalcConstButton::slotSetMode); connect(pbC1, &KCalcConstButton::clicked, this, &KCalculator::slotConstclicked); pbC2->setButtonNumber(1); connect(this, &KCalculator::switchShowAccels, pbC2, &KCalcConstButton::slotSetAccelDisplayMode); connect(this, &KCalculator::switchMode, pbC2, &KCalcConstButton::slotSetMode); connect(pbC2, &KCalcConstButton::clicked, this, &KCalculator::slotConstclicked); pbC3->setButtonNumber(2); connect(this, &KCalculator::switchShowAccels, pbC3, &KCalcConstButton::slotSetAccelDisplayMode); connect(this, &KCalculator::switchMode, pbC3, &KCalcConstButton::slotSetMode); connect(pbC3, &KCalcConstButton::clicked, this, &KCalculator::slotConstclicked); pbC4->setButtonNumber(3); connect(this, &KCalculator::switchShowAccels, pbC4, &KCalcConstButton::slotSetAccelDisplayMode); connect(this, &KCalculator::switchMode, pbC4, &KCalcConstButton::slotSetMode); connect(pbC4, &KCalcConstButton::clicked, this, &KCalculator::slotConstclicked); pbC5->setButtonNumber(4); connect(this, &KCalculator::switchShowAccels, pbC5, &KCalcConstButton::slotSetAccelDisplayMode); connect(this, &KCalculator::switchMode, pbC5, &KCalcConstButton::slotSetMode); connect(pbC5, &KCalcConstButton::clicked, this, &KCalculator::slotConstclicked); pbC6->setButtonNumber(5); connect(this, &KCalculator::switchShowAccels, pbC6, &KCalcConstButton::slotSetAccelDisplayMode); connect(this, &KCalculator::switchMode, pbC6, &KCalcConstButton::slotSetMode); connect(pbC6, &KCalcConstButton::clicked, this, &KCalculator::slotConstclicked); changeButtonNames(); } //------------------------------------------------------------------------------ // Name: setupMiscKeys // Desc: sets up misc keys and related shortcuts //------------------------------------------------------------------------------ void KCalculator::setupMiscKeys() { pbMod->addMode(ModeNormal, i18nc("Modulo", "Mod"), i18n("Modulo")); pbMod->addMode(ModeShift, i18nc("Integer division", "IntDiv"), i18n("Integer division")); connect(this, &KCalculator::switchMode, pbMod, &KCalcButton::slotSetMode); connect(this, &KCalculator::switchShowAccels, pbMod, &KCalcButton::slotSetAccelDisplayMode); pbMod->setShortcut(QKeySequence(Qt::Key_Colon)); connect(pbMod, &KCalcButton::clicked, this, &KCalculator::slotModclicked); pbReci->addMode(ModeNormal, i18nc("Reciprocal", "1/x"), i18n("Reciprocal")); pbReci->addMode(ModeShift, i18nc("n Choose m", "nCm"), i18n("n Choose m")); connect(this, &KCalculator::switchMode, pbReci, &KCalcButton::slotSetMode); connect(this, &KCalculator::switchShowAccels, pbReci, &KCalcButton::slotSetAccelDisplayMode); connect(pbReci, &KCalcButton::clicked, this, &KCalculator::slotReciclicked); pbFactorial->addMode(ModeNormal, i18nc("Factorial", "x!"), i18n("Factorial")); pbFactorial->addMode(ModeShift, QLatin1String("Γ"), i18n("Gamma")); pbFactorial->setShortcut(QKeySequence(Qt::Key_Exclam)); connect(this, &KCalculator::switchShowAccels, pbFactorial, &KCalcButton::slotSetAccelDisplayMode); connect(this, &KCalculator::switchMode, pbFactorial, &KCalcButton::slotSetMode); connect(pbFactorial, &KCalcButton::clicked, this, &KCalculator::slotFactorialclicked); pbSquare->addMode(ModeNormal, i18nc("Square", "x2"), i18n("Square")); pbSquare->addMode(ModeShift, QLatin1String("√x"), i18n("Square root")); pbSquare->setShortcut(QKeySequence(Qt::Key_BracketLeft)); new QShortcut(Qt::Key_twosuperior, pbSquare, SLOT(animateClick())); connect(this, &KCalculator::switchShowAccels, pbSquare, &KCalcButton::slotSetAccelDisplayMode); connect(this, &KCalculator::switchMode, pbSquare, &KCalcButton::slotSetMode); connect(pbSquare, &KCalcButton::clicked, this, &KCalculator::slotSquareclicked); pbPower->addMode(ModeNormal, i18nc("x to the power of y", "xy"), i18n("x to the power of y")); pbPower->addMode(ModeShift, i18nc("x to the power of 1/y", "x1/y"), i18n("x to the power of 1/y")); connect(this, &KCalculator::switchShowAccels, pbPower, &KCalcButton::slotSetAccelDisplayMode); connect(this, &KCalculator::switchMode, pbPower, &KCalcButton::slotSetMode); pbPower->setShortcut(QKeySequence(Qt::Key_AsciiCircum)); connect(pbPower, &KCalcButton::clicked, this, &KCalculator::slotPowerclicked); pbEE->addMode(ModeNormal, QLatin1String("x" "\xb7" "10y"), i18n("Exponent")); connect(this, &KCalculator::switchShowAccels, pbEE, &KCalcButton::slotSetAccelDisplayMode); connect(pbEE, &KCalcButton::clicked, this, &KCalculator::slotEEclicked); } //------------------------------------------------------------------------------ // Name: createConstantsMenu // Desc: additional setup for button keys // NOTE: all alphanumeric shorts set in ui file //------------------------------------------------------------------------------ void KCalculator::setupKeys() { setupNumberKeys(); setupRightKeypad(); setupNumericKeypad(); setupLogicKeys(); setupScientificKeys(); setupStatisticKeys(); setupConstantsKeys(); setupMiscKeys(); // other button lists function_button_list_.append(pbHyp); function_button_list_.append(pbShift); function_button_list_.append(pbEE); function_button_list_.append(pbSin); function_button_list_.append(pbPlusMinus); function_button_list_.append(pbCos); function_button_list_.append(pbReci); function_button_list_.append(pbTan); function_button_list_.append(pbFactorial); function_button_list_.append(pbLog); function_button_list_.append(pbSquare); function_button_list_.append(pbLn); function_button_list_.append(pbPower); function_button_list_.append(pbCube); mem_button_list_.append(pbMemRecall); mem_button_list_.append(pbMemPlusMinus); mem_button_list_.append(pbMemStore); mem_button_list_.append(pbMemClear); mem_button_list_.append(pbClear); mem_button_list_.append(pbAllClear); operation_button_list_.append(pbMultiplication); operation_button_list_.append(pbParenOpen); operation_button_list_.append(pbParenClose); operation_button_list_.append(pbAND); operation_button_list_.append(pbDivision); operation_button_list_.append(pbOR); operation_button_list_.append(pbXOR); operation_button_list_.append(pbPlus); operation_button_list_.append(pbMinus); operation_button_list_.append(pbLsh); operation_button_list_.append(pbRsh); operation_button_list_.append(pbPeriod); operation_button_list_.append(pbEqual); operation_button_list_.append(pbPercent); operation_button_list_.append(pbCmp); operation_button_list_.append(pbMod); } //------------------------------------------------------------------------------ // Name: updateGeometry // Desc: makes all the buttons have reasonable sizes //------------------------------------------------------------------------------ void KCalculator::updateGeometry() { const QSize em = pbAND->fontMetrics().size(0, QLatin1String("M")); int margin = QApplication::style()->pixelMetric(QStyle::PM_ButtonMargin, 0, 0); margin = qMax(qMin(margin / 2, 3), 3); // left pad foreach(QObject *obj, leftPad->children()) { if (KCalcButton *const button = qobject_cast(obj)) { button->setFixedWidth(em.width() * 4 + margin * 2); button->installEventFilter(this); } } // right pad foreach(QObject *obj, rightPad->children()) { KCalcButton *const button = qobject_cast(obj); // let Shift expand freely if (button && button != pbShift) { button->setFixedWidth(em.width() * 3 + margin * 2); button->installEventFilter(this); } } // numeric pad foreach(QObject *obj, numericPad->children()) { if (KCalcButton *const button = qobject_cast(obj)) { // let pb0 expand freely if (button != pb0) { button->setFixedWidth(em.width() * 3 + margin * 2); } button->installEventFilter(this); } } } //------------------------------------------------------------------------------ // Name: slotConstantToDisplay // Desc: inserts a constant //------------------------------------------------------------------------------ void KCalculator::slotConstantToDisplay(const science_constant &const_chosen) { QString val = const_chosen.value; val.replace(QLatin1Char('.'), KNumber::decimalSeparator()); calc_display->setAmount(KNumber(val)); updateDisplay({}); } //------------------------------------------------------------------------------ // Name: slotBaseSelected // Desc: changes the selected numeric base //------------------------------------------------------------------------------ void KCalculator::slotBaseSelected(int base) { int current_base; // set display & statusbar (if item exist in statusbar) statusBar()->setBase(base); switch (base) { case BinMode: current_base = calc_display->setBase(NumBase(2)); calc_display->setStatusText(BaseField, QLatin1String("Bin")); break; case OctMode: current_base = calc_display->setBase(NumBase(8)); calc_display->setStatusText(BaseField, QLatin1String("Oct")); break; case DecMode: current_base = calc_display->setBase(NumBase(10)); calc_display->setStatusText(BaseField, QLatin1String("Dec")); break; case HexMode: current_base = calc_display->setBase(NumBase(16)); calc_display->setStatusText(BaseField, QLatin1String("Hex")); break; default: calc_display->setStatusText(BaseField, QLatin1String("Error")); return; } // Enable the buttons available in this base for (int i = 0; i < current_base; ++i) { (num_button_group_->buttons()[i])->setEnabled(true); } // Disable the buttons not available in this base for (int i = current_base; i < 16; ++i) { (num_button_group_->buttons()[i])->setEnabled(false); } // Only enable the decimal point in decimal pbPeriod->setEnabled(current_base == NB_DECIMAL); // Only enable the x*10^y button in decimal pbEE->setEnabled(current_base == NB_DECIMAL); // Disable buttons that make only sense with floating point numbers if (current_base != NB_DECIMAL) { foreach(QAbstractButton *btn, scientific_buttons_) { btn->setEnabled(false); } } else { foreach(QAbstractButton *btn, scientific_buttons_) { btn->setEnabled(true); } } KCalcSettings::setBaseMode(base); } //------------------------------------------------------------------------------ // Name: keyPressEvent // Desc: handles keypress events //------------------------------------------------------------------------------ void KCalculator::keyPressEvent(QKeyEvent *e) { // Fix for bug #314586 // Basically, on some keyboards such as French, even though the decimal separator - // is "," the numeric keypad has a "." key. So we fake it so people can more seemlessly + // is "," the numeric keypad has a "." key. So we fake it so people can more seamlessly // enter numbers using the keypad if(KNumber::decimalSeparator() != QLatin1String(".")) { if(e->key() == Qt::Key_Period && e->modifiers() & Qt::KeypadModifier) { pbPeriod->animateClick(); } } if (((e->modifiers() & Qt::NoModifier) == 0) || (e->modifiers() & Qt::ShiftModifier)) { switch (e->key()) { case Qt::Key_Backspace: calc_display->deleteLastDigit(); break; } } if (e->key() == Qt::Key_Control) { emit switchShowAccels(true); } } //------------------------------------------------------------------------------ // Name: keyReleaseEvent // Desc: handles keyrelease events //------------------------------------------------------------------------------ void KCalculator::keyReleaseEvent(QKeyEvent *e) { if (e->key() == Qt::Key_Control) { emit switchShowAccels(false); } } //------------------------------------------------------------------------------ // Name: slotAngleSelected // Desc: changes the selected angle system //------------------------------------------------------------------------------ void KCalculator::slotAngleSelected(int mode) { angle_mode_ = mode; statusBar()->setAngleMode(KCalcStatusBar::AngleMode(mode)); switch (mode) { case DegMode: calc_display->setStatusText(AngleField, QLatin1String("Deg")); break; case RadMode: calc_display->setStatusText(AngleField, QLatin1String("Rad")); break; case GradMode: calc_display->setStatusText(AngleField, QLatin1String("Gra")); break; default: // we shouldn't ever end up here angle_mode_ = RadMode; } KCalcSettings::setAngleMode(angle_mode_); } //------------------------------------------------------------------------------ // Name: slotEEclicked -// Desc: starts the entering of numers using scientific notation +// Desc: starts the entering of numbers using scientific notation //------------------------------------------------------------------------------ void KCalculator::slotEEclicked() { calc_display->newCharacter(QLatin1Char('e')); } //------------------------------------------------------------------------------ // Name: slotShifttoggled // Desc: updates the shift state for alternate button functionality //------------------------------------------------------------------------------ void KCalculator::slotShifttoggled(bool flag) { shift_mode_ = flag; emit switchMode(ModeShift, flag); statusBar()->setShiftIndicator(shift_mode_); if (shift_mode_) { calc_display->setStatusText(ShiftField, i18n("Shift")); } else { calc_display->setStatusText(ShiftField, QString()); } } //------------------------------------------------------------------------------ // Name: slotHyptoggled // Desc: updates the Hyp state for alternate trig button functionality //------------------------------------------------------------------------------ void KCalculator::slotHyptoggled(bool flag) { - // toggle between hyperbolic and standart trig functions + // toggle between hyperbolic and standard trig functions hyp_mode_ = flag; emit switchMode(ModeHyperbolic, flag); } //------------------------------------------------------------------------------ // Name: slotMemRecallclicked // Desc: recalls a value from memory //------------------------------------------------------------------------------ void KCalculator::slotMemRecallclicked() { // temp. work-around calc_display->sendEvent(KCalcDisplay::EventReset); calc_display->setAmount(memory_num_); updateDisplay({}); } //------------------------------------------------------------------------------ // Name: slotMemStoreclicked // Desc: stores a value into memory //------------------------------------------------------------------------------ void KCalculator::slotMemStoreclicked() { EnterEqual(); memory_num_ = calc_display->getAmount(); calc_display->setStatusText(MemField, QLatin1String("M")); statusBar()->setMemoryIndicator(true); pbMemRecall->setEnabled(true); } //------------------------------------------------------------------------------ // Name: slotNumberclicked // Desc: user has entered a digit //------------------------------------------------------------------------------ void KCalculator::slotNumberclicked(int number_clicked) { calc_display->enterDigit(number_clicked); core.setOnlyUpdateOperation(false); } //------------------------------------------------------------------------------ // Name: slotSinclicked // Desc: executes the sine function //------------------------------------------------------------------------------ void KCalculator::slotSinclicked() { if (hyp_mode_) { // sinh or arsinh if (!shift_mode_) { core.SinHyp(calc_display->getAmount()); } else { core.AreaSinHyp(calc_display->getAmount()); } } else { // sine or arcsine if (!shift_mode_) { switch (angle_mode_) { case DegMode: core.SinDeg(calc_display->getAmount()); break; case RadMode: core.SinRad(calc_display->getAmount()); break; case GradMode: core.SinGrad(calc_display->getAmount()); break; } } else { switch (angle_mode_) { case DegMode: core.ArcSinDeg(calc_display->getAmount()); break; case RadMode: core.ArcSinRad(calc_display->getAmount()); break; case GradMode: core.ArcSinGrad(calc_display->getAmount()); break; } } } updateDisplay(UPDATE_FROM_CORE); } //------------------------------------------------------------------------------ // Name: slotPlusMinusclicked // Desc: changes sign of number being displayed //------------------------------------------------------------------------------ void KCalculator::slotPlusMinusclicked() { // display can only change sign, when in input mode, otherwise we // need the core to do this. if (!calc_display->sendEvent(KCalcDisplay::EventChangeSign)) { core.InvertSign(calc_display->getAmount()); updateDisplay(UPDATE_FROM_CORE); } } //------------------------------------------------------------------------------ // Name: slotMemPlusMinusclicked // Desc: handles arithmetic on values stored in memory //------------------------------------------------------------------------------ void KCalculator::slotMemPlusMinusclicked() { bool tmp_shift_mode = shift_mode_; // store this, because next command deletes shift_mode_ EnterEqual(); // finish calculation so far, to store result into MEM if (!tmp_shift_mode) { memory_num_ += calc_display->getAmount(); } else { memory_num_ -= calc_display->getAmount(); } pbShift->setChecked(false); statusBar()->setMemoryIndicator(true); calc_display->setStatusText(MemField, i18n("M")); pbMemRecall->setEnabled(true); } //------------------------------------------------------------------------------ // Name: slotSinclicked // Desc: executes the cosine function //------------------------------------------------------------------------------ void KCalculator::slotCosclicked() { if (hyp_mode_) { // cosh or arcosh if (!shift_mode_) { core.CosHyp(calc_display->getAmount()); } else { core.AreaCosHyp(calc_display->getAmount()); } } else { // cosine or arccosine if (!shift_mode_) { switch (angle_mode_) { case DegMode: core.CosDeg(calc_display->getAmount()); break; case RadMode: core.CosRad(calc_display->getAmount()); break; case GradMode: core.CosGrad(calc_display->getAmount()); break; } } else { switch (angle_mode_) { case DegMode: core.ArcCosDeg(calc_display->getAmount()); break; case RadMode: core.ArcCosRad(calc_display->getAmount()); break; case GradMode: core.ArcCosGrad(calc_display->getAmount()); break; } } } updateDisplay(UPDATE_FROM_CORE); } //------------------------------------------------------------------------------ // Name: slotSinclicked // Desc: executes the recipricol function //------------------------------------------------------------------------------ void KCalculator::slotReciclicked() { if (shift_mode_) { core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_BINOM); } else { core.Reciprocal(calc_display->getAmount()); updateDisplay(UPDATE_FROM_CORE); return; } // temp. work-around KNumber tmp_num = calc_display->getAmount(); calc_display->sendEvent(KCalcDisplay::EventReset); calc_display->setAmount(tmp_num); updateDisplay({}); } //------------------------------------------------------------------------------ // Name: slotSinclicked // Desc: executes the tangent function //------------------------------------------------------------------------------ void KCalculator::slotTanclicked() { if (hyp_mode_) { // tanh or artanh if (!shift_mode_) { core.TangensHyp(calc_display->getAmount()); } else { core.AreaTangensHyp(calc_display->getAmount()); } } else { // tan or arctan if (!shift_mode_) { switch (angle_mode_) { case DegMode: core.TangensDeg(calc_display->getAmount()); break; case RadMode: core.TangensRad(calc_display->getAmount()); break; case GradMode: core.TangensGrad(calc_display->getAmount()); break; } } else { switch (angle_mode_) { case DegMode: core.ArcTangensDeg(calc_display->getAmount()); break; case RadMode: core.ArcTangensRad(calc_display->getAmount()); break; case GradMode: core.ArcTangensGrad(calc_display->getAmount()); break; } } } updateDisplay(UPDATE_FROM_CORE); } //------------------------------------------------------------------------------ // Name: slotFactorialclicked // Desc: executes the factorial function //------------------------------------------------------------------------------ void KCalculator::slotFactorialclicked() { // Set WaitCursor, as this operation may take looooong // time and UI frezes with large numbers. User needs some // visual feedback. QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); if (!shift_mode_) { core.Factorial(calc_display->getAmount()); } else { core.Gamma(calc_display->getAmount()); } QApplication::restoreOverrideCursor(); updateDisplay(UPDATE_FROM_CORE); } //------------------------------------------------------------------------------ // Name: slotLogclicked // Desc: executes the Log function //------------------------------------------------------------------------------ void KCalculator::slotLogclicked() { if (!shift_mode_) { core.Log10(calc_display->getAmount()); } else { core.Exp10(calc_display->getAmount()); } updateDisplay(UPDATE_FROM_CORE); } //------------------------------------------------------------------------------ // Name: slotSquareclicked // Desc: executes the x^2 function //------------------------------------------------------------------------------ void KCalculator::slotSquareclicked() { if (!shift_mode_) { core.Square(calc_display->getAmount()); } else { core.SquareRoot(calc_display->getAmount()); } updateDisplay(UPDATE_FROM_CORE); } //------------------------------------------------------------------------------ // Name: slotCubeclicked // Desc: executes the x^3 function //------------------------------------------------------------------------------ void KCalculator::slotCubeclicked() { if (!shift_mode_) { core.Cube(calc_display->getAmount()); } else { core.CubeRoot(calc_display->getAmount()); } updateDisplay(UPDATE_FROM_CORE); } //------------------------------------------------------------------------------ // Name: slotCubeclicked // Desc: executes the ln function //------------------------------------------------------------------------------ void KCalculator::slotLnclicked() { if (!shift_mode_) { core.Ln(calc_display->getAmount()); } else { core.Exp(calc_display->getAmount()); } updateDisplay(UPDATE_FROM_CORE); } //------------------------------------------------------------------------------ // Name: slotPowerclicked // Desc: executes the x^y function //------------------------------------------------------------------------------ void KCalculator::slotPowerclicked() { if (shift_mode_) { core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_PWR_ROOT); pbShift->setChecked(false); } else { core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_POWER); } // temp. work-around KNumber tmp_num = calc_display->getAmount(); calc_display->sendEvent(KCalcDisplay::EventReset); calc_display->setAmount(tmp_num); updateDisplay({}); } //------------------------------------------------------------------------------ // Name: slotMemClearclicked // Desc: executes the MC function //------------------------------------------------------------------------------ void KCalculator::slotMemClearclicked() { memory_num_ = KNumber::Zero; statusBar()->setMemoryIndicator(false); calc_display->setStatusText(MemField, QString()); pbMemRecall->setDisabled(true); } //------------------------------------------------------------------------------ // Name: slotBackspaceclicked // Desc: removes the last input digit //------------------------------------------------------------------------------ void KCalculator::slotBackspaceclicked() { calc_display->deleteLastDigit(); } //------------------------------------------------------------------------------ // Name: slotClearclicked // Desc: clears the display //------------------------------------------------------------------------------ void KCalculator::slotClearclicked() { calc_display->sendEvent(KCalcDisplay::EventClear); } //------------------------------------------------------------------------------ // Name: slotAllClearclicked // Desc: clears everything //------------------------------------------------------------------------------ void KCalculator::slotAllClearclicked() { core.Reset(); calc_display->sendEvent(KCalcDisplay::EventReset); updateDisplay(UPDATE_FROM_CORE); } //------------------------------------------------------------------------------ // Name: slotParenOpenclicked // Desc: starts a sub-expression //------------------------------------------------------------------------------ void KCalculator::slotParenOpenclicked() { core.ParenOpen(calc_display->getAmount()); } //------------------------------------------------------------------------------ // Name: slotParenCloseclicked // Desc: ends a sub-expression //------------------------------------------------------------------------------ void KCalculator::slotParenCloseclicked() { core.ParenClose(calc_display->getAmount()); updateDisplay(UPDATE_FROM_CORE); } //------------------------------------------------------------------------------ // Name: slotANDclicked // Desc: executes a bitwise AND //------------------------------------------------------------------------------ void KCalculator::slotANDclicked() { core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_AND); updateDisplay(UPDATE_FROM_CORE); } //------------------------------------------------------------------------------ // Name: slotMultiplicationclicked // Desc: executes multiplication //------------------------------------------------------------------------------ void KCalculator::slotMultiplicationclicked() { core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_MULTIPLY); updateDisplay(UPDATE_FROM_CORE); } //------------------------------------------------------------------------------ // Name: slotDivisionclicked // Desc: executes division //------------------------------------------------------------------------------ void KCalculator::slotDivisionclicked() { core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_DIVIDE); updateDisplay(UPDATE_FROM_CORE); } //------------------------------------------------------------------------------ // Name: slotORclicked // Desc: executes a bitwise OR //------------------------------------------------------------------------------ void KCalculator::slotORclicked() { core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_OR); updateDisplay(UPDATE_FROM_CORE); } //------------------------------------------------------------------------------ // Name: slotXORclicked // Desc: executes a bitwise XOR //------------------------------------------------------------------------------ void KCalculator::slotXORclicked() { core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_XOR); updateDisplay(UPDATE_FROM_CORE); } //------------------------------------------------------------------------------ // Name: slotPlusclicked // Desc: executes addition //------------------------------------------------------------------------------ void KCalculator::slotPlusclicked() { core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_ADD); updateDisplay(UPDATE_FROM_CORE); } //------------------------------------------------------------------------------ // Name: slotPlusclicked // Desc: executes subtraction //------------------------------------------------------------------------------ void KCalculator::slotMinusclicked() { core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_SUBTRACT); updateDisplay(UPDATE_FROM_CORE); } //------------------------------------------------------------------------------ // Name: slotLeftShiftclicked // Desc: executes a bitwise left shift //------------------------------------------------------------------------------ void KCalculator::slotLeftShiftclicked() { core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_LSH); updateDisplay(UPDATE_FROM_CORE); } //------------------------------------------------------------------------------ // Name: slotLeftShiftclicked // Desc: executes a bitwise right shift //------------------------------------------------------------------------------ void KCalculator::slotRightShiftclicked() { core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_RSH); updateDisplay(UPDATE_FROM_CORE); } //------------------------------------------------------------------------------ // Name: slotPeriodclicked // Desc: enters a decimal into the input stream //------------------------------------------------------------------------------ void KCalculator::slotPeriodclicked() { // i know this isn't locale friendly, should be converted to appropriate // value at lower levels calc_display->newCharacter(QLocale().decimalPoint()); } //------------------------------------------------------------------------------ // Name: EnterEqual // Desc: calculates and displays the result of the pending operations //------------------------------------------------------------------------------ void KCalculator::EnterEqual() { core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_EQUAL); updateDisplay(UPDATE_FROM_CORE | UPDATE_STORE_RESULT); } //------------------------------------------------------------------------------ // Name: slotEqualclicked // Desc: calculates and displays the result of the pending operations //------------------------------------------------------------------------------ void KCalculator::slotEqualclicked() { EnterEqual(); } //------------------------------------------------------------------------------ // Name: slotPercentclicked // Desc: calculates and displays the result of the pending operations as a percent //------------------------------------------------------------------------------ void KCalculator::slotPercentclicked() { core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_PERCENT); updateDisplay(UPDATE_FROM_CORE); } //------------------------------------------------------------------------------ // Name: slotNegateclicked // Desc: executes a bitwise 2's compliment // NOTE: implicitly converts the value to an unsigned quantity //------------------------------------------------------------------------------ void KCalculator::slotNegateclicked() { core.Complement(calc_display->getAmount()); updateDisplay(UPDATE_FROM_CORE); } //------------------------------------------------------------------------------ // Name: slotModclicked // Desc: executes modulous (remainder division) //------------------------------------------------------------------------------ void KCalculator::slotModclicked(){ if (shift_mode_) { core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_INTDIV); } else { core.enterOperation(calc_display->getAmount(), CalcEngine::FUNC_MOD); } updateDisplay(UPDATE_FROM_CORE); } //------------------------------------------------------------------------------ // Name: slotStatNumclicked // Desc: executes Sum function //------------------------------------------------------------------------------ void KCalculator::slotStatNumclicked() { if (!shift_mode_) { core.StatCount(KNumber::Zero); } else { pbShift->setChecked(false); core.StatSum(KNumber::Zero); } updateDisplay(UPDATE_FROM_CORE); } //------------------------------------------------------------------------------ // Name: slotStatMeanclicked // Desc: executes Mean function //------------------------------------------------------------------------------ void KCalculator::slotStatMeanclicked() { if (!shift_mode_) { core.StatMean(KNumber::Zero); } else { pbShift->setChecked(false); core.StatSumSquares(KNumber::Zero); } updateDisplay(UPDATE_FROM_CORE); } //------------------------------------------------------------------------------ // Name: slotStatStdDevclicked // Desc: executes STD function //------------------------------------------------------------------------------ void KCalculator::slotStatStdDevclicked() { if (shift_mode_) { // std (n-1) core.StatStdDeviation(KNumber::Zero); pbShift->setChecked(false); } else { // std (n) core.StatStdSample(KNumber::Zero); } updateDisplay(UPDATE_FROM_CORE); } //------------------------------------------------------------------------------ // Name: slotStatMedianclicked // Desc: executes Median function //------------------------------------------------------------------------------ void KCalculator::slotStatMedianclicked() { if (!shift_mode_) { // std (n-1) core.StatMedian(KNumber::Zero); } else { // std (n) core.StatMedian(KNumber::Zero); pbShift->setChecked(false); } // TODO: it seems two different modes should be implemented, but...? updateDisplay(UPDATE_FROM_CORE); } //------------------------------------------------------------------------------ // Name: slotStatDataInputclicked // Desc: enters a value for statistical functions //------------------------------------------------------------------------------ void KCalculator::slotStatDataInputclicked() { if (!shift_mode_) { core.StatDataNew(calc_display->getAmount()); } else { pbShift->setChecked(false); core.StatDataDel(KNumber::Zero); statusBar()->showMessage(i18n("Last stat item erased"), 3000); } updateDisplay(UPDATE_FROM_CORE); } //------------------------------------------------------------------------------ // Name: slotStatClearDataclicked // Desc: clears memory for statical functions //------------------------------------------------------------------------------ void KCalculator::slotStatClearDataclicked() { if (!shift_mode_) { core.StatClearAll(KNumber::Zero); statusBar()->showMessage(i18n("Stat mem cleared"), 3000); } else { pbShift->setChecked(false); updateDisplay({}); } } //------------------------------------------------------------------------------ // Name: slotConstclicked // Desc: enters a constant //------------------------------------------------------------------------------ void KCalculator::slotConstclicked(int button) { if(KCalcConstButton *btn = qobject_cast(const_buttons_[button])) { if (!shift_mode_) { // set the display to the configured value of constant button // internally, we deal with C locale style numbers, we need to convert QString val = btn->constant(); val.replace(QLatin1Char('.'), KNumber::decimalSeparator()); calc_display->setAmount(KNumber(val)); } else { pbShift->setChecked(false); // internally, we deal with C locale style numbers, we need to convert QString val = calc_display->text(); val.replace(KNumber::decimalSeparator(), QLatin1String(".")); KCalcSettings::setValueConstant(button, val); // below set new tooltip btn->setLabelAndTooltip(); // work around: after storing a number, pressing a digit should start // a new number calc_display->setAmount(calc_display->getAmount()); } updateDisplay({}); } } //------------------------------------------------------------------------------ // Name: showSettings // Desc: opens the shows the settings dialog //------------------------------------------------------------------------------ void KCalculator::showSettings() { // Check if there is already a dialog and if so bring // it to the foreground. if (KConfigDialog::showDialog(QLatin1String("settings"))) { return; } // Create a new dialog with the same name as the above checking code. KConfigDialog *const dialog = new KConfigDialog(this, QLatin1String("settings"), KCalcSettings::self()); // general settings General *const general = new General(nullptr); general->kcfg_Precision->setMaximum(maxprecision); dialog->addPage(general, i18n("General"), QLatin1String("accessories-calculator"), i18n("General Settings")); // font settings Fonts *const fonts = new Fonts(nullptr); dialog->addPage(fonts, i18n("Font"), QLatin1String("preferences-desktop-font"), i18n("Select Display Font")); // color settings Colors *const color = new Colors(nullptr); dialog->addPage(color, i18n("Colors"), QLatin1String("format-fill-color"), i18n("Button & Display Colors")); // constant settings if (!constants_) { constants_ = new Constants(nullptr); } KCalcConstMenu *tmp_menu; tmp_menu = new KCalcConstMenu(this); connect(tmp_menu, &KCalcConstMenu::triggeredConstant, this, &KCalculator::slotChooseScientificConst0); constants_->pushButton0->setMenu(tmp_menu); tmp_menu = new KCalcConstMenu(this); connect(tmp_menu, &KCalcConstMenu::triggeredConstant, this, &KCalculator::slotChooseScientificConst1); constants_->pushButton1->setMenu(tmp_menu); tmp_menu = new KCalcConstMenu(this); connect(tmp_menu, &KCalcConstMenu::triggeredConstant, this, &KCalculator::slotChooseScientificConst2); constants_->pushButton2->setMenu(tmp_menu); tmp_menu = new KCalcConstMenu(this); connect(tmp_menu, &KCalcConstMenu::triggeredConstant, this, &KCalculator::slotChooseScientificConst3); constants_->pushButton3->setMenu(tmp_menu); tmp_menu = new KCalcConstMenu(this); connect(tmp_menu, &KCalcConstMenu::triggeredConstant, this, &KCalculator::slotChooseScientificConst4); constants_->pushButton4->setMenu(tmp_menu); tmp_menu = new KCalcConstMenu(this); connect(tmp_menu, &KCalcConstMenu::triggeredConstant, this, &KCalculator::slotChooseScientificConst5); constants_->pushButton5->setMenu(tmp_menu); dialog->addPage(constants_, i18n("Constants"), QLatin1String("preferences-kcalc-constants"), i18n("Define Constants")); // When the user clicks OK or Apply we want to update our settings. connect(dialog, &KConfigDialog::settingsChanged, this, &KCalculator::updateSettings); // Display the dialog. dialog->show(); } // these 6 slots are just a quick hack, instead of setting the // TextEdit fields in the configuration dialog, we are setting the // Settingvalues themselves!! //------------------------------------------------------------------------------ // Name: slotChooseScientificConst0 // Desc: updates constants value //------------------------------------------------------------------------------ void KCalculator::slotChooseScientificConst0(const science_constant &chosen_const) { constants_->kcfg_valueConstant0->setText(chosen_const.value); constants_->kcfg_nameConstant0->setText(chosen_const.label); } //------------------------------------------------------------------------------ // Name: slotChooseScientificConst1 // Desc: updates constants value //------------------------------------------------------------------------------ void KCalculator::slotChooseScientificConst1(const science_constant &chosen_const) { constants_->kcfg_valueConstant1->setText(chosen_const.value); constants_->kcfg_nameConstant1->setText(chosen_const.label); } //------------------------------------------------------------------------------ // Name: slotChooseScientificConst2 // Desc: updates constants value //------------------------------------------------------------------------------ void KCalculator::slotChooseScientificConst2(const science_constant &chosen_const) { constants_->kcfg_valueConstant2->setText(chosen_const.value); constants_->kcfg_nameConstant2->setText(chosen_const.label); } //------------------------------------------------------------------------------ // Name: slotChooseScientificConst3 // Desc: updates constants value //------------------------------------------------------------------------------ void KCalculator::slotChooseScientificConst3(const science_constant &chosen_const) { constants_->kcfg_valueConstant3->setText(chosen_const.value); constants_->kcfg_nameConstant3->setText(chosen_const.label); } //------------------------------------------------------------------------------ // Name: slotChooseScientificConst4 // Desc: updates constants value //------------------------------------------------------------------------------ void KCalculator::slotChooseScientificConst4(const science_constant &chosen_const) { constants_->kcfg_valueConstant4->setText(chosen_const.value); constants_->kcfg_nameConstant4->setText(chosen_const.label); } //------------------------------------------------------------------------------ // Name: slotChooseScientificConst5 // Desc: updates constants value //------------------------------------------------------------------------------ void KCalculator::slotChooseScientificConst5(const science_constant &chosen_const) { constants_->kcfg_valueConstant5->setText(chosen_const.value); constants_->kcfg_nameConstant5->setText(chosen_const.label); } //------------------------------------------------------------------------------ // Name: slotSetSimpleMode // Desc: sets the calculator to have a simple layout //------------------------------------------------------------------------------ void KCalculator::slotSetSimpleMode() { action_constants_show_->setChecked(false); action_constants_show_->setEnabled(false); action_bitset_show_->setEnabled(false); showMemButtons(false); showScienceButtons(false); showStatButtons(false); showLogicButtons(false); // hide some individual buttons, which are not in one of the above groups pbShift->hide(); pbMod->hide(); pbReci->hide(); pbFactorial->hide(); pbSquare->hide(); pbPower->hide(); pbCube->hide(); pbBackspace->hide(); pbEE->hide(); // delete the constant menu since it doesn't fit delete constants_menu_; constants_menu_ = nullptr; KCalcSettings::setCalculatorMode(KCalcSettings::EnumCalculatorMode::simple); // must be done after setting the calculator mode because the // slotBitsetshow slot should save the state only in numeral mode action_bitset_show_->setChecked(false); } //------------------------------------------------------------------------------ // Name: slotSetScienceMode // Desc: sets the calculator to science mode //------------------------------------------------------------------------------ void KCalculator::slotSetScienceMode() { action_constants_show_->setEnabled(true); action_constants_show_->setChecked(KCalcSettings::showConstants()); action_bitset_show_->setEnabled(false); // show some individual buttons pbShift->show(); pbMod->show(); pbReci->show(); pbFactorial->show(); pbSquare->show(); pbPower->show(); pbCube->show(); pbBackspace->show(); pbEE->show(); // show or hide some groups of buttons showMemButtons(true); showScienceButtons(true); showStatButtons(false); showLogicButtons(false); if(!constants_menu_) { constants_menu_ = createConstantsMenu(); menuBar()->insertMenu((menuBar()->actions)()[2], constants_menu_); } KCalcSettings::setCalculatorMode(KCalcSettings::EnumCalculatorMode::science); // must be done after setting the calculator mode because the // slotBitsetshow slot should save the state only in numeral mode action_bitset_show_->setChecked(false); } //------------------------------------------------------------------------------ // Name: slotSetStatisticMode // Desc: sets the calculator to stats mode //------------------------------------------------------------------------------ void KCalculator::slotSetStatisticMode() { action_constants_show_->setEnabled(true); action_constants_show_->setChecked(KCalcSettings::showConstants()); action_bitset_show_->setEnabled(false); // show some individual buttons pbShift->show(); pbMod->show(); pbReci->show(); pbFactorial->show(); pbSquare->show(); pbPower->show(); pbCube->show(); pbBackspace->show(); pbEE->show(); // show or hide some groups of buttons showMemButtons(true); showScienceButtons(true); showStatButtons(true); showLogicButtons(false); if(!constants_menu_) { constants_menu_ = createConstantsMenu(); menuBar()->insertMenu((menuBar()->actions)()[2], constants_menu_); } KCalcSettings::setCalculatorMode(KCalcSettings::EnumCalculatorMode::statistics); // must be done after setting the calculator mode because the // slotBitsetshow slot should save the state only in numeral mode action_bitset_show_->setChecked(false); } //------------------------------------------------------------------------------ // Name: slotSetNumeralMode // Desc: sets the calculator to numerical ("programmers") mode //------------------------------------------------------------------------------ void KCalculator::slotSetNumeralMode() { action_constants_show_->setChecked(false); action_constants_show_->setEnabled(false); action_bitset_show_->setEnabled(true); action_bitset_show_->setChecked(KCalcSettings::showBitset()); // show some individual buttons pbShift->show(); pbMod->show(); pbReci->show(); pbFactorial->show(); pbSquare->show(); pbPower->show(); pbCube->show(); pbBackspace->show(); pbEE->show(); // show or hide some groups of buttons showMemButtons(true); showScienceButtons(false); showStatButtons(false); showLogicButtons(true); if(!constants_menu_) { constants_menu_ = createConstantsMenu(); menuBar()->insertMenu((menuBar()->actions)()[2], constants_menu_); } KCalcSettings::setCalculatorMode(KCalcSettings::EnumCalculatorMode::numeral); } //------------------------------------------------------------------------------ // Name: showMemButtons // Desc: hides or shows the memory buttons //------------------------------------------------------------------------------ void KCalculator::showMemButtons(bool toggled) { if (toggled) { foreach(QAbstractButton *btn, mem_button_list_) { btn->show(); } } else { foreach(QAbstractButton *btn, mem_button_list_) { btn->hide(); } // these are in the mem_button_list_ but should not be hidden pbClear->show(); pbAllClear->show(); } } //------------------------------------------------------------------------------ // Name: showStatButtons // Desc: hides or shows the stat buttons //------------------------------------------------------------------------------ void KCalculator::showStatButtons(bool toggled) { if (toggled) { foreach(QAbstractButton *btn, stat_buttons_) { btn->show(); } } else { foreach(QAbstractButton *btn, stat_buttons_) { btn->hide(); } } } //------------------------------------------------------------------------------ // Name: showScienceButtons // Desc: hides or shows the science buttons //------------------------------------------------------------------------------ void KCalculator::showScienceButtons(bool toggled) { if (toggled) { foreach(QAbstractButton* btn, scientific_buttons_) { btn->show(); } foreach(QAbstractButton* btn, angle_choose_group_->buttons()) { btn->show(); } setAngle(); statusBar()->setAngleModeIndicatorVisible(true); } else { foreach(QAbstractButton* btn, scientific_buttons_) { btn->hide(); } foreach(QAbstractButton* btn, angle_choose_group_->buttons()) { btn->hide(); } statusBar()->setAngleModeIndicatorVisible(false); calc_display->setStatusText(AngleField, QString()); } } //------------------------------------------------------------------------------ // Name: showLogicButtons // Desc: hides or shows the logic buttons //------------------------------------------------------------------------------ void KCalculator::showLogicButtons(bool toggled) { if (toggled) { mBitset->setEnabled(true); connect(mBitset, &KCalcBitset::valueChanged, this, &KCalculator::slotBitsetChanged); connect(calc_display, &KCalcDisplay::changedAmount, this, &KCalculator::slotUpdateBitset); foreach(QAbstractButton* btn, logic_buttons_) { btn->show(); } setBase(); statusBar()->setBaseIndicatorVisible(true); foreach(QAbstractButton *btn, base_choose_group_->buttons()) { btn->show(); } for (int i = 10; i < 16; ++i) { (num_button_group_->button(i))->show(); } } else { mBitset->setEnabled(false); disconnect(mBitset, &KCalcBitset::valueChanged, this, &KCalculator::slotBitsetChanged); disconnect(calc_display, &KCalcDisplay::changedAmount, this, &KCalculator::slotUpdateBitset); foreach(QAbstractButton* btn, logic_buttons_) { btn->hide(); } // Hide Hex-Buttons, but first switch back to decimal decRadio->animateClick(0); foreach(QAbstractButton *btn, base_choose_group_->buttons()) { btn->hide(); } statusBar()->setBaseIndicatorVisible(false); calc_display->setStatusText(BaseField, QString()); for (int i = 10; i < 16; ++i) { (num_button_group_->button(i))->hide(); } } } //------------------------------------------------------------------------------ // Name: slotConstantsShow // Desc: hides or shows the constants buttons //------------------------------------------------------------------------------ void KCalculator::slotConstantsShow(bool toggled) { if (toggled) { foreach(QAbstractButton *btn, const_buttons_) { btn->show(); } } else { foreach(QAbstractButton *btn, const_buttons_) { btn->hide(); } } KCalcSettings::setShowConstants(toggled); } //------------------------------------------------------------------------------ // Name: slotBitsetshow // Desc: hides or shows the bitset buttons //------------------------------------------------------------------------------ void KCalculator::slotBitsetshow(bool toggled) { mBitset->setVisible(toggled); if (KCalcSettings::calculatorMode() == KCalcSettings::EnumCalculatorMode::numeral) { KCalcSettings::setShowBitset(toggled); } } //------------------------------------------------------------------------------ // Name: slotBitsetshow // Desc: This function is for setting the constant names configured in the // kcalc settings menu. If the user doesn't enter a name for the // constant C1 to C6 is used. //------------------------------------------------------------------------------ void KCalculator::changeButtonNames() { foreach(QAbstractButton *btn, const_buttons_) { if (KCalcConstButton *const constbtn = qobject_cast(btn)) { constbtn->setLabelAndTooltip(); } } } //------------------------------------------------------------------------------ // Name: slotBitsetChanged // Desc: updates the bitset display // NOTE: sets display to *unsigned* value //------------------------------------------------------------------------------ void KCalculator::slotBitsetChanged(quint64 value) { calc_display->setAmount(KNumber(value)); updateDisplay({}); } //------------------------------------------------------------------------------ // Name: slotUpdateBitset // Desc: updates the bitset itself //------------------------------------------------------------------------------ void KCalculator::slotUpdateBitset(const KNumber &nr) { mBitset->setValue(nr.toUint64()); } //------------------------------------------------------------------------------ // Name: updateSettings // Desc: updates the persistent settings //------------------------------------------------------------------------------ void KCalculator::updateSettings() { changeButtonNames(); setColors(); setFonts(); setPrecision(); // Show the result in the app's caption in taskbar (wishlist - bug #52858) disconnect(calc_display, SIGNAL(changedText(QString)), this, nullptr); if (KCalcSettings::captionResult()) { connect(calc_display, &KCalcDisplay::changedText, this, &KCalculator::setWindowTitle); } else { setCaption(QString()); } calc_display->changeSettings(); updateGeometry(); } //------------------------------------------------------------------------------ // Name: updateDisplay // Desc: updates the display //------------------------------------------------------------------------------ void KCalculator::updateDisplay(UpdateFlags flags) { if(flags & UPDATE_FROM_CORE) { calc_display->updateFromCore(core, (flags & UPDATE_STORE_RESULT) != 0); core.setOnlyUpdateOperation(true); } else { calc_display->update(); } pbShift->setChecked(false); } //------------------------------------------------------------------------------ // Name: setColors // Desc: set the various colours //------------------------------------------------------------------------------ void KCalculator::setColors() { calc_display->changeSettings(); KColorScheme schemeButtons(QPalette::Active, KColorScheme::Button); const QColor defaultColor = schemeButtons.background().color(); if (KCalcSettings::numberButtonsColor() == defaultColor && KCalcSettings::functionButtonsColor() == defaultColor && KCalcSettings::statButtonsColor() == defaultColor && KCalcSettings::hexButtonsColor() == defaultColor && KCalcSettings::memoryButtonsColor() == defaultColor && KCalcSettings::operationButtonsColor() == defaultColor) { return; } const QString sheet = QLatin1String("QPushButton { background-color: %1 }"); const QColor numPal(KCalcSettings::numberButtonsColor()); for (int i = 0; i < 10; ++i) { (num_button_group_->button(i))->setStyleSheet(sheet.arg(numPal.name())); } const QColor funcPal(KCalcSettings::functionButtonsColor()); foreach(QAbstractButton *btn, function_button_list_) { btn->setStyleSheet(sheet.arg(funcPal.name())); } const QColor statPal(KCalcSettings::statButtonsColor()); foreach(QAbstractButton *btn, stat_buttons_) { btn->setStyleSheet(sheet.arg(statPal.name())); } const QColor hexPal(KCalcSettings::hexButtonsColor()); for (int i = 10; i < 16; ++i) { (num_button_group_->button(i))->setStyleSheet(sheet.arg(hexPal.name())); } const QColor memPal(KCalcSettings::memoryButtonsColor()); foreach(QAbstractButton *btn, mem_button_list_) { btn->setStyleSheet(sheet.arg(memPal.name())); } const QColor opPal(KCalcSettings::operationButtonsColor()); foreach(QAbstractButton *btn, operation_button_list_) { btn->setStyleSheet(sheet.arg(opPal.name())); } } //------------------------------------------------------------------------------ // Name: setFonts // Desc: set the various fonts //------------------------------------------------------------------------------ void KCalculator::setFonts() { foreach(QObject *obj, leftPad->children()) { if (KCalcButton *const button = qobject_cast(obj)) { button->setFont(KCalcSettings::buttonFont()); } } foreach(QObject *obj, numericPad->children()) { if (KCalcButton *const button = qobject_cast(obj)) { button->setFont(KCalcSettings::buttonFont()); } } foreach(QObject *obj, rightPad->children()) { if (KCalcButton *const button = qobject_cast(obj)) { button->setFont(KCalcSettings::buttonFont()); } } updateGeometry(); } //------------------------------------------------------------------------------ // Name: event // Desc: catch application's palette and font change events //------------------------------------------------------------------------------ bool KCalculator::event(QEvent *e) { switch (e->type()) { case QEvent::ApplicationFontChange: setFonts(); break; case QEvent::ApplicationPaletteChange: setColors(); break; default: break; } return KXmlGuiWindow::event(e); } //------------------------------------------------------------------------------ // Name: setPrecision // Desc: set the precision of the display //------------------------------------------------------------------------------ void KCalculator::setPrecision() { KNumber::setDefaultFloatPrecision(KCalcSettings::precision()); updateDisplay({}); } //------------------------------------------------------------------------------ // Name: setAngle // Desc: sets the angle mode //------------------------------------------------------------------------------ void KCalculator::setAngle() { if (QAbstractButton *const btn = angle_choose_group_->button(KCalcSettings::angleMode())) { btn->animateClick(0); } } //------------------------------------------------------------------------------ // Name: setBase // Desc: sets the numeric base //------------------------------------------------------------------------------ void KCalculator::setBase() { if (QAbstractButton *const btn = base_choose_group_->button(KCalcSettings::baseMode())) { btn->animateClick(0); } } //------------------------------------------------------------------------------ // Name: eventFilter // Desc: general event filter used to track events like drag/drop //------------------------------------------------------------------------------ bool KCalculator::eventFilter(QObject *o, QEvent *e) { switch (e->type()) { case QEvent::DragEnter: { QDragEnterEvent *const ev = reinterpret_cast(e); ev->setAccepted(KColorMimeData::canDecode(ev->mimeData())); return true; } case QEvent::DragLeave: { return true; } case QEvent::Drop: { KCalcButton *const calcButton = qobject_cast(o); if (!calcButton) { return false; } QDropEvent *const ev = reinterpret_cast(e); QColor c = KColorMimeData::fromMimeData(ev->mimeData()); if (c.isValid()) { QString cn = c.name(); QString sheet = QLatin1String("background-color: %1"); QList *list; const int num_but = num_button_group_->buttons().indexOf(calcButton); if (num_but != -1) { // Was it hex-button or normal digit?? if (num_but < 10) { for (int i = 0; i < 10; ++i) { (num_button_group_->buttons()[i])->setStyleSheet(sheet.arg(cn)); } } else { for (int i = 10; i < 16; ++i) { (num_button_group_->buttons()[i])->setStyleSheet(sheet.arg(cn)); } } return true; } else if (function_button_list_.contains(calcButton)) { list = &function_button_list_; } else if (stat_button_list_.contains(calcButton)) { list = &stat_button_list_; } else if (mem_button_list_.contains(calcButton)) { list = &mem_button_list_; } else if (operation_button_list_.contains(calcButton)) { list = &operation_button_list_; } else { return false; } for (int i = 0; i < list->size(); ++i) { list->at(i)->setStyleSheet(sheet.arg(cn)); } } return true; } // FALL THROUGH default: return KXmlGuiWindow::eventFilter(o, e); } } //////////////////////////////////////////////////////////////// // Include the meta-object code for classes in this file // //------------------------------------------------------------------------------ // Name: kdemain // Desc: entry point of the application //------------------------------------------------------------------------------ extern "C" Q_DECL_EXPORT int kdemain(int argc, char *argv[]) { QApplication app(argc, argv); KLocalizedString::setApplicationDomain("kcalc"); /** * enable high dpi support */ app.setAttribute(Qt::AA_UseHighDpiPixmaps, true); Kdelibs4ConfigMigrator migrate(QLatin1String("kcalc")); migrate.setConfigFiles(QStringList() << QLatin1String("kcalcrc")); migrate.setUiFiles(QStringList() << QLatin1String("kcalcui.rc")); migrate.migrate(); KAboutData aboutData(QStringLiteral("kcalc"), i18n("KCalc"), QStringLiteral(KCALC_VERSION_STRING), i18n(description), KAboutLicense::GPL, i18n("Copyright © 2008-2013, Evan Teran\n" "Copyright © 2000-2008, The KDE Team\n" "Copyright © 2003-2005, Klaus Niederkr" "\xc3\xbc" "ger\n" "Copyright © 1996-2000, Bernd Johannes Wuebben"), QStringLiteral(), QStringLiteral("http://utils.kde.org/projects/kcalc")); // Klaus Niederkrueger aboutData.addAuthor(i18n("Klaus Niederkr" "\xc3\xbc" "ger"), QString(), QStringLiteral("kniederk@math.uni-koeln.de")); aboutData.addAuthor(i18n("Bernd Johannes Wuebben"), QString(), QStringLiteral("wuebben@kde.org")); aboutData.addAuthor(i18n("Evan Teran"), i18n("Maintainer"), QStringLiteral("eteran@alum.rit.edu")); aboutData.addAuthor(i18n("Espen Sand"), QString(), QStringLiteral("espen@kde.org")); aboutData.addAuthor(i18n("Chris Howells"), QString(), QStringLiteral("howells@kde.org")); aboutData.addAuthor(i18n("Aaron J. Seigo"), QString(), QStringLiteral("aseigo@olympusproject.org")); aboutData.addAuthor(i18n("Charles Samuels"), QString(), QStringLiteral("charles@altair.dhs.org")); // Rene Merou aboutData.addAuthor(i18n("Ren" "\xc3\xa9" " M" "\xc3\xa9" "rou"), QString(), QStringLiteral("ochominutosdearco@yahoo.es")); aboutData.addAuthor(i18n("Michel Marti"), QString(), QStringLiteral("mma@objectxp.com")); aboutData.addAuthor(i18n("David Johnson"), QString(), QStringLiteral("david@usermode.org")); KAboutData::setApplicationData(aboutData); app.setWindowIcon(QIcon::fromTheme(QLatin1String("accessories-calculator"), app.windowIcon())); QCommandLineParser parser; parser.addHelpOption(); parser.addVersionOption(); aboutData.setupCommandLine(&parser); parser.process(app); aboutData.processCommandLine(&parser); // force system locale to "C" internally [bug 159168] setlocale(LC_NUMERIC, "C"); KNumber::setGroupSeparator(QLocale().groupSeparator()); KNumber::setDecimalSeparator(QString(QLocale().decimalPoint())); KCalculator *calc = new KCalculator(nullptr); calc->show(); return app.exec(); } diff --git a/knumber/knumber.cpp b/knumber/knumber.cpp index 872e5db..d9d7a36 100644 --- a/knumber/knumber.cpp +++ b/knumber/knumber.cpp @@ -1,946 +1,946 @@ /* Copyright (C) 2001 - 2013 Evan Teran evan.teran@gmail.com This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "knumber.h" #include "knumber_base.h" #include "knumber_error.h" #include "knumber_float.h" #include "knumber_fraction.h" #include "knumber_integer.h" #include #include #include #include QString KNumber::GroupSeparator = QLatin1String(","); QString KNumber::DecimalSeparator = QLatin1String("."); const KNumber KNumber::Zero(QLatin1String("0")); const KNumber KNumber::One(QLatin1String("1")); const KNumber KNumber::NegOne(QLatin1String("-1")); const KNumber KNumber::PosInfinity(QLatin1String("inf")); const KNumber KNumber::NegInfinity(QLatin1String("-inf")); const KNumber KNumber::NaN(QLatin1String("nan")); namespace { namespace impl { //------------------------------------------------------------------------------ // Name: increment //------------------------------------------------------------------------------ void increment(QString &str, int position) { for (int i = position; i >= 0; i--) { const char last_char = str[i].toLatin1(); switch (last_char) { case '0': str[i] = QLatin1Char('1'); break; case '1': str[i] = QLatin1Char('2'); break; case '2': str[i] = QLatin1Char('3'); break; case '3': str[i] = QLatin1Char('4'); break; case '4': str[i] = QLatin1Char('5'); break; case '5': str[i] = QLatin1Char('6'); break; case '6': str[i] = QLatin1Char('7'); break; case '7': str[i] = QLatin1Char('8'); break; case '8': str[i] = QLatin1Char('9'); break; case '9': str[i] = QLatin1Char('0'); if (i == 0) { str.prepend(QLatin1Char('1')); } continue; case '.': continue; } break; } } //------------------------------------------------------------------------------ // Name: round //------------------------------------------------------------------------------ void round(QString &str, int precision) { // Cut off if more digits in fractional part than 'precision' int decimalSymbolPos = str.indexOf(QLatin1Char('.')); if (decimalSymbolPos == -1) { if (precision == 0) { return; } else if (precision > 0) { // add dot if missing (and needed) str.append(QLatin1Char('.')); decimalSymbolPos = str.length() - 1; } } // fill up with more than enough zeroes (in case fractional part too short) str.append(QString().fill(QLatin1Char('0'), precision)); // Now decide whether to round up or down const char last_char = str[decimalSymbolPos + precision + 1].toLatin1(); switch (last_char) { case '0': case '1': case '2': case '3': case '4': // nothing to do, rounding down break; case '5': case '6': case '7': case '8': case '9': // rounding up increment(str, decimalSymbolPos + precision); break; default: break; } decimalSymbolPos = str.indexOf(QLatin1Char('.')); str.truncate(decimalSymbolPos + precision + 1); // if precision == 0 delete also '.' if (precision == 0) { str = str.section(QLatin1Char('.'), 0, 0); } } } //------------------------------------------------------------------------------ // Name: round //------------------------------------------------------------------------------ QString round(const QString &s, int precision) { QString tmp = s; if (precision < 0 || !QRegExp(QLatin1String("^[+-]?\\d+(\\.\\d+)*(e[+-]?\\d+)?$")).exactMatch(tmp)) { return s; } // Skip the sign (for now) const bool neg = (tmp[0] == QLatin1Char('-')); if (neg || tmp[0] == QLatin1Char('+')) { tmp.remove(0, 1); } // Split off exponential part (including 'e'-symbol) QString mantString = tmp.section(QLatin1Char('e'), 0, 0, QString::SectionCaseInsensitiveSeps); QString expString = tmp.section(QLatin1Char('e'), 1, 1, QString::SectionCaseInsensitiveSeps | QString::SectionIncludeLeadingSep); if (expString.length() == 1) { expString.clear(); } impl::round(mantString, precision); if (neg) { mantString.prepend(QLatin1Char('-')); } return mantString + expString; } } //------------------------------------------------------------------------------ // Name: setGroupSeparator //------------------------------------------------------------------------------ void KNumber::setGroupSeparator(const QString &ch) { GroupSeparator = ch; } //------------------------------------------------------------------------------ // Name: setDecimalSeparator //------------------------------------------------------------------------------ void KNumber::setDecimalSeparator(const QString &ch) { DecimalSeparator = ch; } //------------------------------------------------------------------------------ // Name: groupSeparator //------------------------------------------------------------------------------ QString KNumber::groupSeparator() { return GroupSeparator; } //------------------------------------------------------------------------------ // Name: decimalSeparator //------------------------------------------------------------------------------ QString KNumber::decimalSeparator() { return DecimalSeparator; } //------------------------------------------------------------------------------ // Name: setDefaultFloatPrecision //------------------------------------------------------------------------------ void KNumber::setDefaultFloatPrecision(int precision) { // Need to transform decimal digits into binary digits const unsigned long int bin_prec = static_cast(double(precision) * M_LN10 / M_LN2 + 1); mpf_set_default_prec(bin_prec); } //------------------------------------------------------------------------------ // Name: setSplitoffIntegerForFractionOutput //------------------------------------------------------------------------------ void KNumber::setSplitoffIntegerForFractionOutput(bool x) { detail::knumber_fraction::set_split_off_integer_for_fraction_output(x); } //------------------------------------------------------------------------------ // Name: setDefaultFractionalInput //------------------------------------------------------------------------------ void KNumber::setDefaultFractionalInput(bool x) { detail::knumber_fraction::set_default_fractional_input(x); } //------------------------------------------------------------------------------ // Name: setDefaultFloatOutput //------------------------------------------------------------------------------ void KNumber::setDefaultFloatOutput(bool x) { detail::knumber_fraction::set_default_fractional_output(!x); } //------------------------------------------------------------------------------ // Name: Pi //------------------------------------------------------------------------------ KNumber KNumber::Pi() { // TODO: after 4.10 release: // create a new constructor which works just like the normal QString // accepting constructor, but allows us to specify separator // characters, this will allow things to be done slightly more // efficiently QString s(QLatin1String("3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068")); s.replace(QLatin1Char('.'), DecimalSeparator); return KNumber(s); } //------------------------------------------------------------------------------ // Name: Euler //------------------------------------------------------------------------------ KNumber KNumber::Euler() { // TODO: after 4.10 release: // create a new constructor which works just like the normal QString // accepting constructor, but allows us to specify separator // characters, this will allow things to be done slightly more // efficiently QString s(QLatin1String("2.7182818284590452353602874713526624977572470936999595749669676277240766303535475945713821785251664274")); s.replace(QLatin1Char('.'), DecimalSeparator); return KNumber(s); } //------------------------------------------------------------------------------ // Name: KNumber //------------------------------------------------------------------------------ KNumber::KNumber() : value_(new detail::knumber_integer(0)) { } //------------------------------------------------------------------------------ // Name: KNumber //------------------------------------------------------------------------------ KNumber::KNumber(const QString &s) : value_(nullptr) { const QRegExp special_regex(QLatin1String("^(inf|-inf|nan)$")); const QRegExp integer_regex(QLatin1String("^[+-]?\\d+$")); const QRegExp fraction_regex(QLatin1String("^[+-]?\\d+/\\d+$")); const QRegExp float_regex(QString(QLatin1String("^([+-]?\\d*)(%1\\d*)?(e([+-]?\\d+))?$")).arg(QRegExp::escape(DecimalSeparator))); if (special_regex.exactMatch(s)) { value_ = new detail::knumber_error(s); } else if (integer_regex.exactMatch(s)) { value_ = new detail::knumber_integer(s); } else if (fraction_regex.exactMatch(s)) { value_ = new detail::knumber_fraction(s); simplify(); } else if (float_regex.exactMatch(s)) { if(detail::knumber_fraction::default_fractional_input) { const QStringList list = float_regex.capturedTexts(); if(list.size() == 5) { const QString ipart = list[1]; const QString fpart = list[2]; const QString epart = list[3]; const int e_val = list[4].toInt(); QString num = ipart + fpart.mid(1); QString den = QLatin1String("1") + QString(fpart.size() - 1, QLatin1Char('0')); if(e_val < 0) { den = den + QString(::abs(e_val), QLatin1Char('0')); } else if(e_val > 0) { num = num + QString(::abs(e_val), QLatin1Char('0')); } value_ = new detail::knumber_fraction(QString(QLatin1String("%1/%2")).arg(num, den)); simplify(); return; } } - // we need to normalize the decimal searator to US style because that's + // we need to normalize the decimal separator to US style because that's // the only type that the GMP function accept QString new_s = s; new_s.replace(DecimalSeparator, QLatin1String(".")); value_ = new detail::knumber_float(new_s); simplify(); } else { value_ = new detail::knumber_error(detail::knumber_error::ERROR_UNDEFINED); } } //------------------------------------------------------------------------------ // Name: KNumber //------------------------------------------------------------------------------ KNumber::KNumber(qint32 value) : value_(new detail::knumber_integer(value)) { } //------------------------------------------------------------------------------ // Name: KNumber //------------------------------------------------------------------------------ KNumber::KNumber(qint64 value) : value_(new detail::knumber_integer(value)) { } //------------------------------------------------------------------------------ // Name: KNumber //------------------------------------------------------------------------------ KNumber::KNumber(quint32 value) : value_(new detail::knumber_integer(value)) { } //------------------------------------------------------------------------------ // Name: KNumber //------------------------------------------------------------------------------ KNumber::KNumber(quint64 value) : value_(new detail::knumber_integer(value)) { } //------------------------------------------------------------------------------ // Name: KNumber //------------------------------------------------------------------------------ KNumber::KNumber(qint64 num, quint64 den) : value_(new detail::knumber_fraction(num, den)) { } //------------------------------------------------------------------------------ // Name: KNumber //------------------------------------------------------------------------------ KNumber::KNumber(quint64 num, quint64 den) : value_(new detail::knumber_fraction(num, den)) { } #ifdef HAVE_LONG_DOUBLE //------------------------------------------------------------------------------ // Name: KNumber //------------------------------------------------------------------------------ KNumber::KNumber(long double value) : value_(new detail::knumber_float(value)) { simplify(); } #endif //------------------------------------------------------------------------------ // Name: KNumber //------------------------------------------------------------------------------ KNumber::KNumber(double value) : value_(new detail::knumber_float(value)) { simplify(); } //------------------------------------------------------------------------------ // Name: KNumber //------------------------------------------------------------------------------ KNumber::KNumber(const KNumber &other) : value_(nullptr) { if(&other != this) { value_ = other.value_->clone(); } } //------------------------------------------------------------------------------ // Name: ~KNumber //------------------------------------------------------------------------------ KNumber::~KNumber() { delete value_; } //------------------------------------------------------------------------------ // Name: type //------------------------------------------------------------------------------ KNumber::Type KNumber::type() const { if(dynamic_cast(value_)) { return TYPE_INTEGER; } else if(dynamic_cast(value_)) { return TYPE_FLOAT; } else if(dynamic_cast(value_)) { return TYPE_FRACTION; } else if(dynamic_cast(value_)) { return TYPE_ERROR; } else { Q_ASSERT(0); return TYPE_ERROR; } } //------------------------------------------------------------------------------ // Name: operator= //------------------------------------------------------------------------------ KNumber &KNumber::operator=(const KNumber &rhs) { KNumber(rhs).swap(*this); return *this; } //------------------------------------------------------------------------------ // Name: swap //------------------------------------------------------------------------------ void KNumber::swap(KNumber &other) { qSwap(value_, other.value_); } //------------------------------------------------------------------------------ // Name: integerPart //------------------------------------------------------------------------------ KNumber KNumber::integerPart() const { KNumber x(*this); if(detail::knumber_integer *const p = dynamic_cast(value_)) { // NO-OP Q_UNUSED(p); } else if(detail::knumber_float *const p = dynamic_cast(value_)) { detail::knumber_base *v = new detail::knumber_integer(p); qSwap(v, x.value_); delete v; } else if(detail::knumber_fraction *const p = dynamic_cast(value_)) { detail::knumber_base *v = new detail::knumber_integer(p); qSwap(v, x.value_); delete v; } else if(detail::knumber_error *const p = dynamic_cast(value_)) { // NO-OP Q_UNUSED(p); } else { Q_ASSERT(0); } return x; } //------------------------------------------------------------------------------ // Name: simplify //------------------------------------------------------------------------------ void KNumber::simplify() { if(value_->is_integer()) { if(detail::knumber_integer *const p = dynamic_cast(value_)) { // NO-OP Q_UNUSED(p); } else if(detail::knumber_float *const p = dynamic_cast(value_)) { detail::knumber_base *v = new detail::knumber_integer(p); qSwap(v, value_); delete v; } else if(detail::knumber_fraction *const p = dynamic_cast(value_)) { detail::knumber_base *v = new detail::knumber_integer(p); qSwap(v, value_); delete v; } else if(detail::knumber_error *const p = dynamic_cast(value_)) { // NO-OP Q_UNUSED(p); } else { Q_ASSERT(0); } } } //------------------------------------------------------------------------------ // Name: operator+= //------------------------------------------------------------------------------ KNumber &KNumber::operator+=(const KNumber &rhs) { value_ = value_->add(rhs.value_); simplify(); return *this; } //------------------------------------------------------------------------------ // Name: operator-= //------------------------------------------------------------------------------ KNumber &KNumber::operator-=(const KNumber &rhs) { value_ = value_->sub(rhs.value_); simplify(); return *this; } //------------------------------------------------------------------------------ // Name: operator*= //------------------------------------------------------------------------------ KNumber &KNumber::operator*=(const KNumber &rhs) { value_ = value_->mul(rhs.value_); simplify(); return *this; } //------------------------------------------------------------------------------ // Name: operator/= //------------------------------------------------------------------------------ KNumber &KNumber::operator/=(const KNumber &rhs) { // Fix for bug #330577, x /0 is undefined, not infinity // Also indirectly fixes bug #329897, tan(90) is undefined, not infinity if(rhs == Zero) { *this = NaN; return *this; } value_ = value_->div(rhs.value_); simplify(); return *this; } //------------------------------------------------------------------------------ // Name: operator%= //------------------------------------------------------------------------------ KNumber &KNumber::operator%=(const KNumber &rhs) { value_ = value_->mod(rhs.value_); simplify(); return *this; } //------------------------------------------------------------------------------ // Name: operator&= //------------------------------------------------------------------------------ KNumber &KNumber::operator&=(const KNumber &rhs) { value_ = value_->bitwise_and(rhs.value_); return *this; } //------------------------------------------------------------------------------ // Name: operator|= //------------------------------------------------------------------------------ KNumber &KNumber::operator|=(const KNumber &rhs) { value_ = value_->bitwise_or(rhs.value_); return *this; } //------------------------------------------------------------------------------ // Name: operator^= //------------------------------------------------------------------------------ KNumber &KNumber::operator^=(const KNumber &rhs) { value_ = value_->bitwise_xor(rhs.value_); return *this; } //------------------------------------------------------------------------------ // Name: operator<< //------------------------------------------------------------------------------ KNumber &KNumber::operator<<=(const KNumber &rhs) { value_ = value_->bitwise_shift(rhs.value_); return *this; } //------------------------------------------------------------------------------ // Name: operator>>= //------------------------------------------------------------------------------ KNumber &KNumber::operator>>=(const KNumber &rhs) { const KNumber rhs_neg(-rhs); value_ = value_->bitwise_shift(rhs_neg.value_); return *this; } //------------------------------------------------------------------------------ // Name: operator- //------------------------------------------------------------------------------ KNumber KNumber::operator-() const { KNumber x(*this); x.value_ = x.value_->neg(); return x; } //------------------------------------------------------------------------------ // Name: operator~ //------------------------------------------------------------------------------ KNumber KNumber::operator~() const { KNumber x(*this); x.value_ = x.value_->cmp(); return x; } //------------------------------------------------------------------------------ // Name: toQString //------------------------------------------------------------------------------ QString KNumber::toQString(int width, int precision) const { if(value_->is_zero()) { return QLatin1String("0"); } QString s; if(detail::knumber_integer *const p = dynamic_cast(value_)) { if(width > 0) { s = detail::knumber_float(p).toString(width); } else { s = value_->toString(width); } } else if(detail::knumber_float *const p = dynamic_cast(value_)) { if(width > 0) { s = value_->toString(width); } else { s = value_->toString(3 * mpf_get_default_prec() / 10); } } else if(detail::knumber_fraction *const p = dynamic_cast(value_)) { s = value_->toString(width); } else { return value_->toString(width); } // now do some rounding to make sure things are displayed reasonably if (precision >= 0) { return round(s, precision); } else { return s; } } //------------------------------------------------------------------------------ // Name: toUint64 //------------------------------------------------------------------------------ quint64 KNumber::toUint64() const { return value_->toUint64(); } //------------------------------------------------------------------------------ // Name: toInt64 //------------------------------------------------------------------------------ qint64 KNumber::toInt64() const { return value_->toInt64(); } //------------------------------------------------------------------------------ // Name: abs //------------------------------------------------------------------------------ KNumber KNumber::abs() const { KNumber z(*this); z.value_ = z.value_->abs(); z.simplify(); return z; } //------------------------------------------------------------------------------ // Name: cbrt //------------------------------------------------------------------------------ KNumber KNumber::cbrt() const { KNumber z(*this); z.value_ = z.value_->cbrt(); z.simplify(); return z; } //------------------------------------------------------------------------------ // Name: sqrt //------------------------------------------------------------------------------ KNumber KNumber::sqrt() const { KNumber z(*this); z.value_ = z.value_->sqrt(); z.simplify(); return z; } //------------------------------------------------------------------------------ // Name: pow //------------------------------------------------------------------------------ KNumber KNumber::pow(const KNumber &x) const { // Fix for bug #330711 (pow(0, -x) was causing crashes // Fix for bug #330597 (pow(0,0) was 1 now it is NaN // Thanks to Raushan Kumar for identifying the issue and submitting // patches if(*this == Zero && x <= Zero) { return NaN; } // if the LHS is a special then we can use this function // no matter what, cause the result is a special too if(!dynamic_cast(value_)) { // number much bigger than this tend to crash GMP with // an abort if(x > KNumber(QLatin1String("1000000000"))) { return PosInfinity; } } KNumber z(*this); z.value_ = z.value_->pow(x.value_); z.simplify(); return z; } //------------------------------------------------------------------------------ // Name: sin //------------------------------------------------------------------------------ KNumber KNumber::sin() const { KNumber z(*this); z.value_ = z.value_->sin(); z.simplify(); return z; } //------------------------------------------------------------------------------ // Name: cos //------------------------------------------------------------------------------ KNumber KNumber::cos() const { KNumber z(*this); z.value_ = z.value_->cos(); z.simplify(); return z; } //------------------------------------------------------------------------------ // Name: tan //------------------------------------------------------------------------------ KNumber KNumber::tan() const { KNumber z(*this); z.value_ = z.value_->tan(); z.simplify(); return z; } //------------------------------------------------------------------------------ // Name: tgamma //------------------------------------------------------------------------------ KNumber KNumber::tgamma() const { KNumber z(*this); if(z > KNumber(QLatin1String("10000000000"))) { return PosInfinity; } z.value_ = z.value_->tgamma(); z.simplify(); return z; } //------------------------------------------------------------------------------ // Name: asin //------------------------------------------------------------------------------ KNumber KNumber::asin() const { KNumber z(*this); z.value_ = z.value_->asin(); z.simplify(); return z; } //------------------------------------------------------------------------------ // Name: acos //------------------------------------------------------------------------------ KNumber KNumber::acos() const { KNumber z(*this); z.value_ = z.value_->acos(); z.simplify(); return z; } //------------------------------------------------------------------------------ // Name: atan //------------------------------------------------------------------------------ KNumber KNumber::atan() const { KNumber z(*this); z.value_ = z.value_->atan(); z.simplify(); return z; } //------------------------------------------------------------------------------ // Name: sinh //------------------------------------------------------------------------------ KNumber KNumber::sinh() const { KNumber z(*this); z.value_ = z.value_->sinh(); z.simplify(); return z; } //------------------------------------------------------------------------------ // Name: cosh //------------------------------------------------------------------------------ KNumber KNumber::cosh() const { KNumber z(*this); z.value_ = z.value_->cosh(); z.simplify(); return z; } //------------------------------------------------------------------------------ // Name: tanh //------------------------------------------------------------------------------ KNumber KNumber::tanh() const { KNumber z(*this); z.value_ = z.value_->tanh(); z.simplify(); return z; } //------------------------------------------------------------------------------ // Name: asinh //------------------------------------------------------------------------------ KNumber KNumber::asinh() const { KNumber z(*this); z.value_ = z.value_->asinh(); z.simplify(); return z; } //------------------------------------------------------------------------------ // Name: acosh //------------------------------------------------------------------------------ KNumber KNumber::acosh() const { KNumber z(*this); z.value_ = z.value_->acosh(); z.simplify(); return z; } //------------------------------------------------------------------------------ // Name: atanh //------------------------------------------------------------------------------ KNumber KNumber::atanh() const { KNumber z(*this); z.value_ = z.value_->atanh(); z.simplify(); return z; } //------------------------------------------------------------------------------ // Name: factorial //------------------------------------------------------------------------------ KNumber KNumber::factorial() const { KNumber z(*this); // number much bigger than this tend to crash GMP with // an abort if(z > KNumber(QLatin1String("10000000000"))) { return PosInfinity; } z.value_ = z.value_->factorial(); z.simplify(); return z; } //------------------------------------------------------------------------------ // Name: log2 //------------------------------------------------------------------------------ KNumber KNumber::log2() const { KNumber z(*this); z.value_ = z.value_->log2(); z.simplify(); return z; } //------------------------------------------------------------------------------ // Name: log10 //------------------------------------------------------------------------------ KNumber KNumber::log10() const { KNumber z(*this); z.value_ = z.value_->log10(); z.simplify(); return z; } //------------------------------------------------------------------------------ // Name: ln //------------------------------------------------------------------------------ KNumber KNumber::ln() const { KNumber z(*this); z.value_ = z.value_->ln(); z.simplify(); return z; } //------------------------------------------------------------------------------ // Name: floor //------------------------------------------------------------------------------ KNumber KNumber::floor() const { KNumber z(*this); z.value_ = z.value_->floor(); z.simplify(); return z; } //------------------------------------------------------------------------------ // Name: ceil //------------------------------------------------------------------------------ KNumber KNumber::ceil() const { KNumber z(*this); z.value_ = z.value_->ceil(); z.simplify(); return z; } //------------------------------------------------------------------------------ // Name: exp2 //------------------------------------------------------------------------------ KNumber KNumber::exp2() const { KNumber z(*this); z.value_ = z.value_->exp2(); z.simplify(); return z; } //------------------------------------------------------------------------------ // Name: exp10 //------------------------------------------------------------------------------ KNumber KNumber::exp10() const { KNumber z(*this); z.value_ = z.value_->exp10(); z.simplify(); return z; } //------------------------------------------------------------------------------ // Name: exp //------------------------------------------------------------------------------ KNumber KNumber::exp() const { KNumber z(*this); z.value_ = z.value_->exp(); z.simplify(); return z; } //------------------------------------------------------------------------------ // Name: bin //------------------------------------------------------------------------------ KNumber KNumber::bin(const KNumber &x) const { KNumber z(*this); z.value_ = z.value_->bin(x.value_); z.simplify(); return z; } diff --git a/knumber/knumber_fraction.cpp b/knumber/knumber_fraction.cpp index 289cc59..d651e6d 100644 --- a/knumber/knumber_fraction.cpp +++ b/knumber/knumber_fraction.cpp @@ -1,909 +1,909 @@ /* Copyright (C) 2001 - 2013 Evan Teran evan.teran@gmail.com This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include "knumber_integer.h" #include "knumber_float.h" #include "knumber_fraction.h" #include "knumber_error.h" #include #include namespace detail { bool knumber_fraction::default_fractional_input = false; bool knumber_fraction::default_fractional_output = true; bool knumber_fraction::split_off_integer_for_fraction_output = false; //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ void knumber_fraction::set_default_fractional_input(bool value) { default_fractional_input = value; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ void knumber_fraction::set_default_fractional_output(bool value) { default_fractional_output = value; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ void knumber_fraction::set_split_off_integer_for_fraction_output(bool value) { split_off_integer_for_fraction_output = value; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_fraction::knumber_fraction(const QString &s) { mpq_init(mpq_); mpq_set_str(mpq_, s.toLatin1().constData(), 10); mpq_canonicalize(mpq_); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_fraction::knumber_fraction(qint64 num, quint64 den) { mpq_init(mpq_); mpq_set_si(mpq_, num, den); mpq_canonicalize(mpq_); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_fraction::knumber_fraction(quint64 num, quint64 den) { mpq_init(mpq_); mpq_set_ui(mpq_, num, den); mpq_canonicalize(mpq_); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_fraction::knumber_fraction(mpq_t mpq) { mpq_init(mpq_); mpq_set(mpq_, mpq); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_fraction::knumber_fraction(const knumber_fraction *value) { mpq_init(mpq_); mpq_set(mpq_, value->mpq_); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_fraction::knumber_fraction(const knumber_integer *value) { mpq_init(mpq_); mpq_set_z(mpq_, value->mpz_); } #if 0 //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_fraction::knumber_fraction(const knumber_float *value) { mpq_init(mpq_); mpq_set_f(mpq_, value->mpf_); } #endif //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_base *knumber_fraction::clone() { return new knumber_fraction(this); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_fraction::~knumber_fraction() { mpq_clear(mpq_); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ bool knumber_fraction::is_integer() const { return (mpz_cmp_ui(mpq_denref(mpq_), 1) == 0); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_base *knumber_fraction::add(knumber_base *rhs) { if(knumber_integer *const p = dynamic_cast(rhs)) { knumber_fraction q(p); mpq_add(mpq_, mpq_, q.mpq_); return this; } else if(knumber_float *const p = dynamic_cast(rhs)) { knumber_float *f = new knumber_float(this); delete this; return f->add(p); } else if(knumber_fraction *const p = dynamic_cast(rhs)) { mpq_add(mpq_, mpq_, p->mpq_); return this; } else if(knumber_error *const p = dynamic_cast(rhs)) { knumber_error *e = new knumber_error(p); delete this; return e; } Q_ASSERT(0); return nullptr; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_base *knumber_fraction::sub(knumber_base *rhs) { if(knumber_integer *const p = dynamic_cast(rhs)) { knumber_fraction q(p); mpq_sub(mpq_, mpq_, q.mpq_); return this; } else if(knumber_float *const p = dynamic_cast(rhs)) { knumber_float *f = new knumber_float(this); delete this; return f->sub(p); } else if(knumber_fraction *const p = dynamic_cast(rhs)) { mpq_sub(mpq_, mpq_, p->mpq_); return this; } else if(knumber_error *const p = dynamic_cast(rhs)) { knumber_error *e = new knumber_error(p); delete this; return e->neg(); } Q_ASSERT(0); return nullptr; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_base *knumber_fraction::mul(knumber_base *rhs) { if(knumber_integer *const p = dynamic_cast(rhs)) { knumber_fraction q(p); mpq_mul(mpq_, mpq_, q.mpq_); return this; } else if(knumber_float *const p = dynamic_cast(rhs)) { knumber_float *q = new knumber_float(this); delete this; return q->mul(p); } else if(knumber_fraction *const p = dynamic_cast(rhs)) { mpq_mul(mpq_, mpq_, p->mpq_); return this; } else if(knumber_error *const p = dynamic_cast(rhs)) { if(is_zero()) { delete this; knumber_error *e = new knumber_error(knumber_error::ERROR_UNDEFINED); return e; } if(sign() < 0) { delete this; knumber_error *e = new knumber_error(p); return e->neg(); } else { delete this; knumber_error *e = new knumber_error(p); return e; } } Q_ASSERT(0); return nullptr; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_base *knumber_fraction::div(knumber_base *rhs) { if(rhs->is_zero()) { if(sign() < 0) { delete this; return new knumber_error(knumber_error::ERROR_NEG_INFINITY); } else { delete this; return new knumber_error(knumber_error::ERROR_POS_INFINITY); } } if(knumber_integer *const p = dynamic_cast(rhs)) { knumber_fraction f(p); return div(&f); } else if(knumber_float *const p = dynamic_cast(rhs)) { knumber_float *f = new knumber_float(this); delete this; return f->div(p); } else if(knumber_fraction *const p = dynamic_cast(rhs)) { mpq_div(mpq_, mpq_, p->mpq_); return this; } else if(knumber_error *const p = dynamic_cast(rhs)) { if(p->sign() > 0) { delete this; return new knumber_integer(0); } else if(p->sign() < 0) { delete this; return new knumber_integer(0); } knumber_error *e = new knumber_error(p); delete this; return e; } Q_ASSERT(0); return nullptr; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_base *knumber_fraction::mod(knumber_base *rhs) { if(rhs->is_zero()) { delete this; return new knumber_error(knumber_error::ERROR_UNDEFINED); } // NOTE: we don't support modulus operations with non-integer operands mpq_set_d(mpq_, 0); return this; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_base *knumber_fraction::bitwise_and(knumber_base *rhs) { Q_UNUSED(rhs); delete this; // NOTE: we don't support bitwise operations with non-integer operands return new knumber_integer(0); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_base *knumber_fraction::bitwise_xor(knumber_base *rhs) { Q_UNUSED(rhs); delete this; // NOTE: we don't support bitwise operations with non-integer operands return new knumber_integer(0); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_base *knumber_fraction::bitwise_or(knumber_base *rhs) { Q_UNUSED(rhs); delete this; // NOTE: we don't support bitwise operations with non-integer operands return new knumber_integer(0); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_base *knumber_fraction::bitwise_shift(knumber_base *rhs) { Q_UNUSED(rhs); delete this; // NOTE: we don't support bitwise operations with non-integer operands return new knumber_error(knumber_error::ERROR_UNDEFINED); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_base *knumber_fraction::neg() { mpq_neg(mpq_, mpq_); return this; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_base *knumber_fraction::abs() { mpq_abs(mpq_, mpq_); return this; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_base *knumber_fraction::cmp() { delete this; return new knumber_error(knumber_error::ERROR_UNDEFINED); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_base *knumber_fraction::sqrt() { if(sign() < 0) { delete this; return new knumber_error(knumber_error::ERROR_UNDEFINED); } if(mpz_perfect_square_p(mpq_numref(mpq_)) && mpz_perfect_square_p(mpq_denref(mpq_))) { mpz_t num; mpz_t den; mpz_init(num); mpz_init(den); mpq_get_num(num, mpq_); mpq_get_den(den, mpq_); mpz_sqrt(num, num); mpz_sqrt(den, den); mpq_set_num(mpq_, num); mpq_set_den(mpq_, den); mpq_canonicalize(mpq_); mpz_clear(num); mpz_clear(den); return this; } else { knumber_float *f = new knumber_float(this); delete this; return f->sqrt(); } } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_base *knumber_fraction::cbrt() { // TODO: figure out how to properly use mpq_numref/mpq_denref here mpz_t num; mpz_t den; mpz_init(num); mpz_init(den); mpq_get_num(num, mpq_); mpq_get_den(den, mpq_); if(mpz_root(num, num, 3) && mpz_root(den, den, 3)) { mpq_set_num(mpq_, num); mpq_set_den(mpq_, den); mpq_canonicalize(mpq_); mpz_clear(num); mpz_clear(den); return this; } else { mpz_clear(num); mpz_clear(den); knumber_float *f = new knumber_float(this); delete this; return f->cbrt(); } } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_base *knumber_fraction::factorial() { if(sign() < 0) { delete this; return new knumber_error(knumber_error::ERROR_UNDEFINED); } knumber_integer *i = new knumber_integer(this); delete this; return i->factorial(); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_base *knumber_fraction::pow(knumber_base *rhs) { // TODO: figure out how to properly use mpq_numref/mpq_denref here if(knumber_integer *const p = dynamic_cast(rhs)) { mpz_t num; mpz_t den; mpz_init(num); mpz_init(den); mpq_get_num(num, mpq_); mpq_get_den(den, mpq_); mpz_pow_ui(num, num, mpz_get_ui(p->mpz_)); mpz_pow_ui(den, den, mpz_get_ui(p->mpz_)); mpq_set_num(mpq_, num); mpq_set_den(mpq_, den); mpq_canonicalize(mpq_); mpz_clear(num); mpz_clear(den); if(p->sign() < 0) { return reciprocal(); } else { return this; } } else if(knumber_float *const p = dynamic_cast(rhs)) { Q_UNUSED(p); knumber_float *f = new knumber_float(this); delete this; return f->pow(rhs); } else if(knumber_fraction *const p = dynamic_cast(rhs)) { // ok, so if any part of the number is > 1,000,000, then we risk // the pow function overflowing... so we'll just convert to float to be safe - // TODO: at some point, we should figure out exactly what the threashold is + // TODO: at some point, we should figure out exactly what the threshold is // and if there is a better way to determine if the pow function will // overflow. if(mpz_cmpabs_ui(mpq_numref(mpq_), 1000000) > 0 || mpz_cmpabs_ui(mpq_denref(mpq_), 1000000) > 0 || mpz_cmpabs_ui(mpq_numref(p->mpq_), 1000000) > 0 || mpz_cmpabs_ui(mpq_denref(p->mpq_), 1000000) > 0) { knumber_float *f = new knumber_float(this); delete this; return f->pow(rhs); } mpz_t lhs_num; mpz_t lhs_den; mpz_t rhs_num; mpz_t rhs_den; mpz_init(lhs_num); mpz_init(lhs_den); mpz_init(rhs_num); mpz_init(rhs_den); mpq_get_num(lhs_num, mpq_); mpq_get_den(lhs_den, mpq_); mpq_get_num(rhs_num, p->mpq_); mpq_get_den(rhs_den, p->mpq_); mpz_pow_ui(lhs_num, lhs_num, mpz_get_ui(rhs_num)); mpz_pow_ui(lhs_den, lhs_den, mpz_get_ui(rhs_num)); if(mpz_sgn(lhs_num) < 0 && mpz_even_p(rhs_den)) { mpz_clear(lhs_num); mpz_clear(lhs_den); mpz_clear(rhs_num); mpz_clear(rhs_den); delete this; return new knumber_error(knumber_error::ERROR_UNDEFINED); } if(mpz_sgn(lhs_den) < 0 && mpz_even_p(rhs_den)) { mpz_clear(lhs_num); mpz_clear(lhs_den); mpz_clear(rhs_num); mpz_clear(rhs_den); delete this; return new knumber_error(knumber_error::ERROR_UNDEFINED); } const int n1 = mpz_root(lhs_num, lhs_num, mpz_get_ui(rhs_den)); const int n2 = mpz_root(lhs_den, lhs_den, mpz_get_ui(rhs_den)); if(n1 && n2) { mpq_set_num(mpq_, lhs_num); mpq_set_den(mpq_, lhs_den); mpq_canonicalize(mpq_); mpz_clear(lhs_num); mpz_clear(lhs_den); mpz_clear(rhs_num); mpz_clear(rhs_den); if(p->sign() < 0) { return reciprocal(); } else { return this; } } else { mpz_clear(lhs_num); mpz_clear(lhs_den); mpz_clear(rhs_num); mpz_clear(rhs_den); knumber_float *f = new knumber_float(this); delete this; return f->pow(rhs); } } else if(knumber_error *const p = dynamic_cast(rhs)) { if(p->sign() > 0) { knumber_error *e = new knumber_error(knumber_error::ERROR_POS_INFINITY); delete this; return e; } else if(p->sign() < 0) { knumber_integer *n = new knumber_integer(0); delete this; return n; } else { knumber_error *e = new knumber_error(knumber_error::ERROR_UNDEFINED); delete this; return e; } } Q_ASSERT(0); return nullptr; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_base *knumber_fraction::sin() { knumber_float *f = new knumber_float(this); delete this; return f->sin(); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_base *knumber_fraction::floor() { knumber_float *f = new knumber_float(this); delete this; return f->floor(); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_base *knumber_fraction::ceil() { knumber_float *f = new knumber_float(this); delete this; return f->ceil(); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_base *knumber_fraction::cos() { knumber_float *f = new knumber_float(this); delete this; return f->cos(); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_base *knumber_fraction::tgamma() { knumber_float *f = new knumber_float(this); delete this; return f->tgamma(); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_base *knumber_fraction::tan() { knumber_float *f = new knumber_float(this); delete this; return f->tan(); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_base *knumber_fraction::asin() { knumber_float *f = new knumber_float(this); delete this; return f->asin(); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_base *knumber_fraction::acos() { knumber_float *f = new knumber_float(this); delete this; return f->acos(); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_base *knumber_fraction::atan() { knumber_float *f = new knumber_float(this); delete this; return f->atan(); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_base *knumber_fraction::sinh() { knumber_float *f = new knumber_float(this); delete this; return f->sinh(); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_base *knumber_fraction::cosh() { knumber_float *f = new knumber_float(this); delete this; return f->cosh(); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_base *knumber_fraction::tanh() { knumber_float *f = new knumber_float(this); delete this; return f->tanh(); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_base *knumber_fraction::asinh() { knumber_float *f = new knumber_float(this); delete this; return f->asinh(); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_base *knumber_fraction::acosh() { knumber_float *f = new knumber_float(this); delete this; return f->acosh(); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_base *knumber_fraction::atanh() { knumber_float *f = new knumber_float(this); delete this; return f->atanh(); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ int knumber_fraction::compare(knumber_base *rhs) { if(knumber_integer *const p = dynamic_cast(rhs)) { knumber_fraction f(p); return mpq_cmp(mpq_, f.mpq_); } else if(knumber_float *const p = dynamic_cast(rhs)) { knumber_float f(this); return f.compare(p); } else if(knumber_fraction *const p = dynamic_cast(rhs)) { return mpq_cmp(mpq_, p->mpq_); } else if(knumber_error *const p = dynamic_cast(rhs)) { // NOTE: any number compared to NaN/Inf/-Inf always compares less // at the moment return -1; } Q_ASSERT(0); return 0; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ QString knumber_fraction::toString(int precision) const { if(knumber_fraction::default_fractional_output) { // TODO: figure out how to properly use mpq_numref/mpq_denref here knumber_integer integer_part(this); if(split_off_integer_for_fraction_output && !integer_part.is_zero()) { mpz_t num; mpz_init(num); mpq_get_num(num, mpq_); knumber_integer integer_part_1(this); mpz_mul(integer_part.mpz_, integer_part.mpz_, mpq_denref(mpq_)); mpz_sub(num, num, integer_part.mpz_); if(mpz_sgn(num) < 0) { mpz_neg(num, num); } const size_t size = gmp_snprintf(nullptr, 0, "%Zd %Zd/%Zd", integer_part_1.mpz_, num, mpq_denref(mpq_)) + 1; QScopedArrayPointer buf(new char[size]); gmp_snprintf(&buf[0], size, "%Zd %Zd/%Zd", integer_part_1.mpz_, num, mpq_denref(mpq_)); mpz_clear(num); return QLatin1String(&buf[0]); } else { mpz_t num; mpz_init(num); mpq_get_num(num, mpq_); const size_t size = gmp_snprintf(nullptr, 0, "%Zd/%Zd", num, mpq_denref(mpq_)) + 1; QScopedArrayPointer buf(new char[size]); gmp_snprintf(&buf[0], size, "%Zd/%Zd", num, mpq_denref(mpq_)); mpz_clear(num); return QLatin1String(&buf[0]); } } else { return knumber_float(this).toString(precision); } } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ bool knumber_fraction::is_zero() const { return mpq_sgn(mpq_) == 0; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ int knumber_fraction::sign() const { return mpq_sgn(mpq_); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_base *knumber_fraction::reciprocal() { mpq_inv(mpq_, mpq_); return this; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_integer *knumber_fraction::numerator() const { mpz_t num; mpz_init(num); mpq_get_num(num, mpq_); knumber_integer *n = new knumber_integer(num); mpz_clear(num); return n; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_integer *knumber_fraction::denominator() const { mpz_t den; mpz_init(den); mpq_get_den(den, mpq_); knumber_integer *n = new knumber_integer(den); mpz_clear(den); return n; } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_base *knumber_fraction::log2() { knumber_float *f = new knumber_float(this); delete this; return f->log2(); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_base *knumber_fraction::log10() { knumber_float *f = new knumber_float(this); delete this; return f->log10(); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_base *knumber_fraction::ln() { knumber_float *f = new knumber_float(this); delete this; return f->ln(); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_base *knumber_fraction::exp2() { knumber_float *f = new knumber_float(this); delete this; return f->exp2(); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_base *knumber_fraction::exp10() { knumber_float *f = new knumber_float(this); delete this; return f->exp10(); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_base *knumber_fraction::exp() { knumber_float *f = new knumber_float(this); delete this; return f->exp(); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ quint64 knumber_fraction::toUint64() const { return knumber_integer(this).toUint64(); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ qint64 knumber_fraction::toInt64() const { return knumber_integer(this).toInt64(); } //------------------------------------------------------------------------------ // Name: //------------------------------------------------------------------------------ knumber_base *knumber_fraction::bin(knumber_base *rhs) { Q_UNUSED(rhs); delete this; return new knumber_error(knumber_error::ERROR_UNDEFINED); } } diff --git a/stats.cpp b/stats.cpp index 9ea76ef..a301163 100644 --- a/stats.cpp +++ b/stats.cpp @@ -1,213 +1,213 @@ /* Copyright (C) 2001 - 2013 Evan Teran evan.teran@gmail.com Copyright (C) 1996 - 2000 Bernd Johannes Wuebben wuebben@kde.org This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "stats.h" //------------------------------------------------------------------------------ // Name: KStats // Desc: constructor //------------------------------------------------------------------------------ KStats::KStats() : error_flag_(false) { } //------------------------------------------------------------------------------ // Name: ~KStats // Desc: destructor //------------------------------------------------------------------------------ KStats::~KStats() { } //------------------------------------------------------------------------------ // Name: clearAll // Desc: empties the data set //------------------------------------------------------------------------------ void KStats::clearAll() { data_.clear(); } //------------------------------------------------------------------------------ // Name: enterData // Desc: adds an item to the data set //------------------------------------------------------------------------------ void KStats::enterData(const KNumber &data) { data_.push_back(data); } //------------------------------------------------------------------------------ // Name: clearLast -// Desc: remoaves the last item from the data set +// Desc: removes the last item from the data set //------------------------------------------------------------------------------ void KStats::clearLast() { if(!data_.isEmpty()) { data_.pop_back(); } } //------------------------------------------------------------------------------ // Name: sum // Desc: calculates the SUM of all values in the data set //------------------------------------------------------------------------------ KNumber KStats::sum() const { KNumber result = KNumber::Zero; Q_FOREACH(const KNumber &x, data_) { result += x; } return result; } //------------------------------------------------------------------------------ // Name: median // Desc: calculates the MEDIAN of all values in the data set //------------------------------------------------------------------------------ KNumber KStats::median() { KNumber result = KNumber::Zero; size_t index; unsigned int bound = count(); if (bound == 0) { error_flag_ = true; return KNumber::Zero; } if (bound == 1) return data_.at(0); // need to copy data_-list, because sorting afterwards QVector tmp_data(data_); qSort(tmp_data); if (bound & 1) { // odd index = (bound - 1) / 2 + 1; result = tmp_data.at(index - 1); } else { // even index = bound / 2; result = ((tmp_data.at(index - 1)) + (tmp_data.at(index))) / KNumber(2); } return result; } //------------------------------------------------------------------------------ // Name: std_kernel // Desc: calculates the STD Kernel of all values in the data set //------------------------------------------------------------------------------ KNumber KStats::std_kernel() { KNumber result = KNumber::Zero; const KNumber mean_value = mean(); if(mean_value.type() != KNumber::TYPE_ERROR) { Q_FOREACH(const KNumber &x, data_) { result += (x - mean_value) * (x - mean_value); } } return result; } //------------------------------------------------------------------------------ // Name: sum_of_squares // Desc: calculates the SUM of all values in the data set (each squared) //------------------------------------------------------------------------------ KNumber KStats::sum_of_squares() const { KNumber result = KNumber::Zero; Q_FOREACH(const KNumber &x, data_) { result += (x * x); } return result; } //------------------------------------------------------------------------------ // Name: mean // Desc: calculates the MEAN of all values in the data set //------------------------------------------------------------------------------ KNumber KStats::mean() { if (data_.isEmpty()) { error_flag_ = true; return KNumber::Zero; } return (sum() / KNumber(count())); } //------------------------------------------------------------------------------ // Name: std // Desc: calculates the STANDARD DEVIATION of all values in the data set //------------------------------------------------------------------------------ KNumber KStats::std() { if (data_.isEmpty()) { error_flag_ = true; return KNumber::Zero; } return (std_kernel() / KNumber(count())).sqrt(); } //------------------------------------------------------------------------------ // Name: sample_std // Desc: calculates the SAMPLE STANDARD DEVIATION of all values in the data set //------------------------------------------------------------------------------ KNumber KStats::sample_std() { KNumber result = KNumber::Zero; if (count() < 2) { error_flag_ = true; return KNumber::Zero; } result = (std_kernel() / KNumber(count() - 1)).sqrt(); return result; } //------------------------------------------------------------------------------ // Name: count // Desc: returns the amount of values in the data set //------------------------------------------------------------------------------ int KStats::count() const { return data_.size(); } //------------------------------------------------------------------------------ // Name: error // Desc: returns the error state AND clears it //------------------------------------------------------------------------------ bool KStats::error() { bool value = error_flag_; error_flag_ = false; return value; }