diff --git a/qml/Main.qml b/qml/Main.qml index 389f9fe..f0ae300 100644 --- a/qml/Main.qml +++ b/qml/Main.qml @@ -22,14 +22,12 @@ ApplicationWindow { Layout.fillWidth: true ColumnLayout { - anchors.fill: parent spacing: 10 TextField { id: numberInput placeholderText: "Enter a number" // NOTE: We can't use the IntValidator here, since it doesn't support 64-bit values (long long) - // Entering invalid numbers might cause unexpected behavior (will be fed to parseInt). Layout.fillWidth: true font.pixelSize: 16 onTextChanged: factorizationController.reset() @@ -51,16 +49,10 @@ ApplicationWindow { } Button { - text: factorizationController.isPaused ? "Reset" : factorizationController.isRunning ? "Pause" : "Reset" + text: "Pause" Layout.fillWidth: true - enabled: factorizationController.isRunning || factorizationController.isPaused - onClicked: { - if (factorizationController.isPaused) { - factorizationController.reset(); - } else { - factorizationController.stop(); - } - } + enabled: factorizationController.isRunning + onClicked: factorizationController.stop() } } } @@ -69,9 +61,7 @@ ApplicationWindow { GroupBox { title: "Settings" Layout.fillWidth: true - ColumnLayout { - anchors.fill: parent spacing: 10 RowLayout { @@ -99,64 +89,37 @@ ApplicationWindow { } } - RowLayout { - Layout.fillWidth: true - - CheckBox { - text: "Stop at sqrt(n)" - checked: factorizationController.useSqrtOptimization - onCheckedChanged: factorizationController.useSqrtOptimization = checked - } - - CheckBox { - text: "Pause when factor found" - checked: factorizationController.pauseOnFound - onCheckedChanged: factorizationController.pauseOnFound = checked - } + CheckBox { + text: "Stop at sqrt(n)" + checked: true + onCheckedChanged: factorizationController.useSqrtOptimization = checked } } } + ProgressBar { + Layout.fillWidth: true + from: 0 + to: 100 + value: factorizationController.progress + } + GroupBox { title: "Current Status" Layout.fillWidth: true - ColumnLayout { - anchors.fill: parent spacing: 5 - Text { - text: "Current Number (being factorized): " + factorizationController.curFactNumber - font.pixelSize: 14 - } - Text { text: "Current Factor: " + factorizationController.currentFactor font.pixelSize: 14 + Layout.alignment: Qt.AlignHCenter } Text { - text: "Stop Factor: " + factorizationController.stopFactor + text: "Current Number (being factorized): " + factorizationController.curFactNumber font.pixelSize: 14 - } - - Item { - Layout.fillWidth: true - Layout.preferredHeight: 25 - - ProgressBar { - anchors.fill: parent - to: 100 - value: factorizationController.progress - } - - Text { - text: factorizationController.progress.toFixed(1) + "%" - anchors.centerIn: parent - font.pixelSize: 16 - color: "black" - font.bold: true - } + Layout.alignment: Qt.AlignHCenter } } } @@ -174,7 +137,7 @@ ApplicationWindow { } Text { - text: factorizationController.useSqrtOptimization ? "Note: Only factors up to sqrt(n) are searched." : "Warning: Searching all factors (inefficient)." + text: factorizationController.useSqrtOptimization ? "Note: Only factors up to sqrt(n) are searched." : "Note: Searching all factors (slower)." font.pixelSize: 12 Layout.alignment: Qt.AlignHCenter } diff --git a/src/FactorizationController.cpp b/src/FactorizationController.cpp index dc9cf79..803c0ab 100644 --- a/src/FactorizationController.cpp +++ b/src/FactorizationController.cpp @@ -3,37 +3,30 @@ #include FactorizationController::FactorizationController(QObject* parent) : - QObject{parent}, m_isRunning(false), m_useSqrtOptimization(true), m_pauseOnFound(false), m_iterationsPerCycle(1), m_currentFactNumber(0), m_originalNumber(0), - m_currentFactor(0), m_stopFactor(0) { + QObject{parent}, m_isRunning(false), m_useSqrtOptimization(true), m_iterationsPerCycle(1), m_currentFactNumber(0), m_currentFactor(2) { assert(connect(&m_timer, &QTimer::timeout, this, &FactorizationController::onTimerTick)); } -unsigned long long FactorizationController::number() const { +long long FactorizationController::number() const { return m_originalNumber; } -unsigned long long FactorizationController::curFactNumber() const { +long long FactorizationController::curFactNumber() const { return m_currentFactNumber; } -double FactorizationController::progress() const { - // If the original number is set to 0, the computation wasn't yet initialized / was reset. - // If the current factor is at 2, the computation has just started, return early to avoid - // zero division issues. - if (m_originalNumber == 0 || m_currentFactor <= 2) - return 0; - - // If the current number being factorized is 1, we must be done, all factors were found - // Alternatively, we're also done when the current factor passes the stop factor. - if (m_currentFactNumber == 1 || m_currentFactor > m_stopFactor) +int FactorizationController::progress() const { + // If current factor is at or below 2 already, we must be done, + // stopFactor can never be less than 2, that makes no sense. + if (m_currentFactNumber == 1 || m_currentFactor <= 2 || m_currentFactor > m_stopFactor) return 100; // Determine the progress based on the current factor, in comparison to stop factor. // since factor being <= 2 means 100%, we sub 2 here. double progress = static_cast(m_currentFactor - 2) / static_cast(m_stopFactor - 2); - // Return the value as percentage - return std::clamp(progress * 100, 0.0, 100.0); + // Return the value as int percentage + return static_cast(std::clamp(progress * 100, 0.0, 100.0)); } bool FactorizationController::isFinished() const { @@ -58,29 +51,7 @@ void FactorizationController::setUseSqrtOptimization(bool value) { m_useSqrtOptimization = value; emit useSqrtOptimizationChanged(); - - // We're in a reset state - if (m_originalNumber == 0) - return; - - if (m_useSqrtOptimization) - m_stopFactor = static_cast(std::sqrt(m_currentFactNumber)); - else - m_stopFactor = m_currentFactNumber - 1; - emit stopFactorChanged(); - emit progressChanged(); -} - -bool FactorizationController::pauseOnFound() const { - return m_pauseOnFound; -} - -void FactorizationController::setPauseOnFound(bool value) { - if (value == m_pauseOnFound) - return; - - m_pauseOnFound = value; - emit pauseOnFoundChanged(); + reset(); } int FactorizationController::iterationsPerCycle() const { @@ -95,31 +66,21 @@ void FactorizationController::setIterationsPerCycle(int number) { emit iterationsPerCycleChanged(); } -unsigned long long FactorizationController::currentFactor() const { +long long FactorizationController::currentFactor() const { return m_currentFactor; } -unsigned long long FactorizationController::stopFactor() const { - return m_stopFactor; -} - -QList FactorizationController::factors() const { +QList FactorizationController::factors() const { return m_factors; } -void FactorizationController::start(unsigned long long number) { +void FactorizationController::start(long long number) { m_originalNumber = number; m_currentFactNumber = number; m_currentFactor = 2; m_isRunning = true; m_isFinished = false; m_factors.clear(); - if (m_useSqrtOptimization) { - // we could also just compute this every time, but sqrt is pretty expensive - m_stopFactor = static_cast(std::sqrt(m_currentFactNumber)); - } else { - m_stopFactor = m_currentFactNumber - 1; - } emit isRunningChanged(); emit isFinishedChanged(); emit numberChanged(); @@ -127,7 +88,13 @@ void FactorizationController::start(unsigned long long number) { emit progressChanged(); emit factorsChanged(); emit curFactNumberChanged(); - emit stopFactorChanged(); + + if (m_useSqrtOptimization) { + // we could also just compute this every time, but sqrt is pretty expensive + m_stopFactor = static_cast(std::sqrt(m_currentFactNumber)); + } else { + m_stopFactor = m_currentFactNumber - 1; + } m_timer.start(0); } @@ -167,17 +134,13 @@ void FactorizationController::reset() { return; m_isPaused = false; - m_originalNumber = 0; - m_currentFactNumber = 0; - m_currentFactor = 0; - m_stopFactor = 0; + m_currentFactNumber = m_originalNumber; + m_currentFactor = 2; m_factors.clear(); emit isPausedChanged(); emit currentFactorChanged(); - emit curFactNumberChanged(); - emit factorsChanged(); - emit stopFactorChanged(); emit progressChanged(); + emit factorsChanged(); } void FactorizationController::onTimerTick() { @@ -226,16 +189,12 @@ void FactorizationController::factorize() { // the new number being factorized, rather than keeping it at the original number. // (This might make the progress bar jump radically) if (m_useSqrtOptimization) { - m_stopFactor = static_cast(std::sqrt(m_currentFactNumber)); + m_stopFactor = static_cast(std::sqrt(m_currentFactNumber)); } else { m_stopFactor = m_currentFactNumber - 1; } - emit stopFactorChanged(); emit progressChanged(); - if (m_pauseOnFound) - stop(); - // Don't increase current factor, keep dividing by it until no longer divisible } else { m_currentFactor++; diff --git a/src/FactorizationController.h b/src/FactorizationController.h index af4d3e9..c3c6ab7 100644 --- a/src/FactorizationController.h +++ b/src/FactorizationController.h @@ -26,13 +26,11 @@ class FactorizationController : public QObject { Q_PROPERTY(bool isPaused READ isPaused NOTIFY isPausedChanged) Q_PROPERTY(int iterationsPerCycle READ iterationsPerCycle WRITE setIterationsPerCycle NOTIFY iterationsPerCycleChanged) Q_PROPERTY(bool useSqrtOptimization READ useSqrtOptimization WRITE setUseSqrtOptimization NOTIFY useSqrtOptimizationChanged) - Q_PROPERTY(bool pauseOnFound READ pauseOnFound WRITE setPauseOnFound NOTIFY pauseOnFoundChanged) - Q_PROPERTY(unsigned long long number READ number NOTIFY numberChanged) - Q_PROPERTY(unsigned long long curFactNumber READ curFactNumber NOTIFY curFactNumberChanged) - Q_PROPERTY(unsigned long long currentFactor READ currentFactor NOTIFY currentFactorChanged) - Q_PROPERTY(unsigned long long stopFactor READ stopFactor NOTIFY stopFactorChanged) - Q_PROPERTY(double progress READ progress NOTIFY progressChanged) - Q_PROPERTY(QList factors READ factors NOTIFY factorsChanged) + Q_PROPERTY(long long number READ number NOTIFY numberChanged) + Q_PROPERTY(long long curFactNumber READ curFactNumber NOTIFY curFactNumberChanged) + Q_PROPERTY(long long currentFactor READ currentFactor NOTIFY currentFactorChanged) + Q_PROPERTY(int progress READ progress NOTIFY progressChanged) + Q_PROPERTY(QList factors READ factors NOTIFY factorsChanged) public: explicit FactorizationController(QObject* parent = nullptr); @@ -43,7 +41,7 @@ class FactorizationController : public QObject { * @brief Gets the current progress of factorization. * @return The progress percentage (0-100). */ - double progress() const; + int progress() const; /** * @brief Checks if the factorization process is running. @@ -89,17 +87,11 @@ class FactorizationController : public QObject { */ bool useSqrtOptimization() const; - /** - * @brief Checks whether the computation should be paused once a new factor is found. - * @return True if the computation will get paused on new factor being found, otherwise False. - */ - bool pauseOnFound() const; - /** * @brief Gets the original number being factorized. * @return The number being factorized. */ - unsigned long long number() const; + long long number() const; /** * @brief The current number being factorized. @@ -108,7 +100,7 @@ class FactorizationController : public QObject { * As the factorization process is going on, the number being factorized might change * from the original number, as we're dividing it by the found factors. */ - unsigned long long curFactNumber() const; + long long curFactNumber() const; /** * @brief Gets the current factor being tested. @@ -118,17 +110,7 @@ class FactorizationController : public QObject { * is a factor, going one by one. This returns the current factor (to be checked in the * next iteration). */ - unsigned long long currentFactor() const; - - /** - * @brief Get the number at which the factorization process will stop - * @return The current stop factor. - * - * The stop factor determines at which factor will the factorization process be stopped. - * If sqrt optimizations are enabled, this will generally be the square root of the number - * currently being factorized. If not, it will be the number being factorized - 1. - */ - unsigned long long stopFactor() const; + long long currentFactor() const; /** * @brief Gets the list of discovered factors (may not be complete). @@ -138,7 +120,7 @@ class FactorizationController : public QObject { * be complete (if the computation is still running). If you need to know whether you * can trust this result, check isFinished first. */ - QList factors() const; + QList factors() const; // endregion // region: Setters @@ -167,20 +149,11 @@ class FactorizationController : public QObject { * Generally, there's no reason to disable this optimization, however, if you wish to * perform a slower search, it is a way to achieve that. * - * This value can be changed even as a computation is ongoing; if you do so, the stop factor - * will change immediately, which will very likely cause the progress bar to rapidly change. - * It is possible that after enabling, the computation will immediately finish, as the stop - * factor will be less than the sqrt(x). + * Note that changing this value while the computation is in progress will reset the + * computation. */ void setUseSqrtOptimization(bool value); - /** - * @brief Enable or disable auto-pausing on new factor being found. - * - * This value can be changed even as a computation is ongoing. - */ - void setPauseOnFound(bool value); - // endregion // region: Functions @@ -191,7 +164,7 @@ class FactorizationController : public QObject { * This will start a 0-tick timer, which triggers a partial computation on each run, * to let the event loop cycle in between. This implementation does NOT rely on threads. */ - Q_INVOKABLE void start(unsigned long long number); + Q_INVOKABLE void start(long long number); /** * @brief Stops the ongoing factorization process. @@ -224,14 +197,12 @@ class FactorizationController : public QObject { void isFinishedChanged(); void isPausedChanged(); void useSqrtOptimizationChanged(); - void pauseOnFoundChanged(); void iterationsPerCycleChanged(); void numberChanged(); void currentFactorChanged(); void factorsChanged(); void progressChanged(); void curFactNumberChanged(); - void stopFactorChanged(); private slots: void onTimerTick(); @@ -241,13 +212,12 @@ class FactorizationController : public QObject { bool m_isFinished; ///< Indicates whether the factorization process is done. bool m_isPaused; ///< Indicates whether the factorization process is paused (can be resumed). bool m_useSqrtOptimization; ///< Indicates whether to use the sqrt optimization - bool m_pauseOnFound; ///< Indicates whether the computation should be paused when a new factor is found. int m_iterationsPerCycle; ///< The number of iterations to perform per cycle. - unsigned long long m_currentFactNumber; ///< The number currently being factorized. - unsigned long long m_originalNumber; ///< The original input number. - unsigned long long m_currentFactor; ///< The current divisor being checked. - unsigned long long m_stopFactor; ///< The stopping limit (square root of original number, saved for efficiency). - QList m_factors; ///< List of discovered prime factors. + long long m_currentFactNumber; ///< The number currently being factorized. + long long m_originalNumber; ///< The original input number. + long long m_currentFactor; ///< The current divisor being checked. + long long m_stopFactor; ///< The stopping limit (square root of original number, saved for efficiency). + QList m_factors; ///< List of discovered prime factors. QTimer m_timer; ///< Timer for stepwise execution. /**