Compare commits
	
		
			10 commits
		
	
	
		
			cff0316c0a
			...
			c62f027656
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| c62f027656 | |||
| d54c6743e7 | |||
| 48ddf3d5ae | |||
| 767f706fea | |||
| c4d48e982a | |||
| def77613c6 | |||
| 18b6e69e9f | |||
| 12caef0a51 | |||
| c58697b126 | |||
| 028f492c32 | 
					 3 changed files with 173 additions and 65 deletions
				
			
		
							
								
								
									
										83
									
								
								qml/Main.qml
									
										
									
									
									
								
							
							
						
						
									
										83
									
								
								qml/Main.qml
									
										
									
									
									
								
							|  | @ -22,12 +22,14 @@ 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() | ||||
|  | @ -49,10 +51,16 @@ ApplicationWindow { | |||
|                     } | ||||
| 
 | ||||
|                     Button { | ||||
|                         text: "Pause" | ||||
|                         text: factorizationController.isPaused ? "Reset" : factorizationController.isRunning ? "Pause" : "Reset" | ||||
|                         Layout.fillWidth: true | ||||
|                         enabled: factorizationController.isRunning | ||||
|                         onClicked: factorizationController.stop() | ||||
|                         enabled: factorizationController.isRunning || factorizationController.isPaused | ||||
|                         onClicked: { | ||||
|                             if (factorizationController.isPaused) { | ||||
|                                 factorizationController.reset(); | ||||
|                             } else { | ||||
|                                 factorizationController.stop(); | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|  | @ -61,7 +69,9 @@ ApplicationWindow { | |||
|         GroupBox { | ||||
|             title: "Settings" | ||||
|             Layout.fillWidth: true | ||||
| 
 | ||||
|             ColumnLayout { | ||||
|                 anchors.fill: parent | ||||
|                 spacing: 10 | ||||
| 
 | ||||
|                 RowLayout { | ||||
|  | @ -89,37 +99,64 @@ ApplicationWindow { | |||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 CheckBox { | ||||
|                     text: "Stop at sqrt(n)" | ||||
|                     checked: true | ||||
|                     onCheckedChanged: factorizationController.useSqrtOptimization = checked | ||||
|                 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 | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         ProgressBar { | ||||
|             Layout.fillWidth: true | ||||
|             from: 0 | ||||
|             to: 100 | ||||
|             value: factorizationController.progress | ||||
|         } | ||||
| 
 | ||||
|         GroupBox { | ||||
|             title: "Current Status" | ||||
|             Layout.fillWidth: true | ||||
|             ColumnLayout { | ||||
|                 spacing: 5 | ||||
| 
 | ||||
|                 Text { | ||||
|                     text: "Current Factor: " + factorizationController.currentFactor | ||||
|                     font.pixelSize: 14 | ||||
|                     Layout.alignment: Qt.AlignHCenter | ||||
|                 } | ||||
|             ColumnLayout { | ||||
|                 anchors.fill: parent | ||||
|                 spacing: 5 | ||||
| 
 | ||||
|                 Text { | ||||
|                     text: "Current Number (being factorized): " + factorizationController.curFactNumber | ||||
|                     font.pixelSize: 14 | ||||
|                     Layout.alignment: Qt.AlignHCenter | ||||
|                 } | ||||
| 
 | ||||
|                 Text { | ||||
|                     text: "Current Factor: " + factorizationController.currentFactor | ||||
|                     font.pixelSize: 14 | ||||
|                 } | ||||
| 
 | ||||
|                 Text { | ||||
|                     text: "Stop Factor: " + factorizationController.stopFactor | ||||
|                     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 | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | @ -137,7 +174,7 @@ ApplicationWindow { | |||
|         } | ||||
| 
 | ||||
|         Text { | ||||
|             text: factorizationController.useSqrtOptimization ? "Note: Only factors up to sqrt(n) are searched." : "Note: Searching all factors (slower)." | ||||
|             text: factorizationController.useSqrtOptimization ? "Note: Only factors up to sqrt(n) are searched." : "Warning: Searching all factors (inefficient)." | ||||
|             font.pixelSize: 12 | ||||
|             Layout.alignment: Qt.AlignHCenter | ||||
|         } | ||||
|  |  | |||
|  | @ -3,30 +3,37 @@ | |||
| #include <cmath> | ||||
| 
 | ||||
| FactorizationController::FactorizationController(QObject* parent) : | ||||
|     QObject{parent}, m_isRunning(false), m_useSqrtOptimization(true), m_iterationsPerCycle(1), m_currentFactNumber(0), m_currentFactor(2) { | ||||
|     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) { | ||||
|     assert(connect(&m_timer, &QTimer::timeout, this, &FactorizationController::onTimerTick)); | ||||
| } | ||||
| 
 | ||||
| long long FactorizationController::number() const { | ||||
| unsigned long long FactorizationController::number() const { | ||||
|     return m_originalNumber; | ||||
| } | ||||
| 
 | ||||
| long long FactorizationController::curFactNumber() const { | ||||
| unsigned long long FactorizationController::curFactNumber() const { | ||||
|     return m_currentFactNumber; | ||||
| } | ||||
| 
 | ||||
| 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) | ||||
| 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) | ||||
|         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<double>(m_currentFactor - 2) / static_cast<double>(m_stopFactor - 2); | ||||
| 
 | ||||
|     // Return the value as int percentage
 | ||||
|     return static_cast<int>(std::clamp(progress * 100, 0.0, 100.0)); | ||||
|     // Return the value as percentage
 | ||||
|     return std::clamp(progress * 100, 0.0, 100.0); | ||||
| } | ||||
| 
 | ||||
| bool FactorizationController::isFinished() const { | ||||
|  | @ -51,7 +58,29 @@ void FactorizationController::setUseSqrtOptimization(bool value) { | |||
| 
 | ||||
|     m_useSqrtOptimization = value; | ||||
|     emit useSqrtOptimizationChanged(); | ||||
|     reset(); | ||||
| 
 | ||||
|     // We're in a reset state
 | ||||
|     if (m_originalNumber == 0) | ||||
|         return; | ||||
| 
 | ||||
|     if (m_useSqrtOptimization) | ||||
|         m_stopFactor = static_cast<unsigned long long>(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(); | ||||
| } | ||||
| 
 | ||||
| int FactorizationController::iterationsPerCycle() const { | ||||
|  | @ -66,21 +95,31 @@ void FactorizationController::setIterationsPerCycle(int number) { | |||
|     emit iterationsPerCycleChanged(); | ||||
| } | ||||
| 
 | ||||
| long long FactorizationController::currentFactor() const { | ||||
| unsigned long long FactorizationController::currentFactor() const { | ||||
|     return m_currentFactor; | ||||
| } | ||||
| 
 | ||||
| QList<long long> FactorizationController::factors() const { | ||||
| unsigned long long FactorizationController::stopFactor() const { | ||||
|     return m_stopFactor; | ||||
| } | ||||
| 
 | ||||
| QList<unsigned long long> FactorizationController::factors() const { | ||||
|     return m_factors; | ||||
| } | ||||
| 
 | ||||
| void FactorizationController::start(long long number) { | ||||
| void FactorizationController::start(unsigned 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<unsigned long long>(std::sqrt(m_currentFactNumber)); | ||||
|     } else { | ||||
|         m_stopFactor = m_currentFactNumber - 1; | ||||
|     } | ||||
|     emit isRunningChanged(); | ||||
|     emit isFinishedChanged(); | ||||
|     emit numberChanged(); | ||||
|  | @ -88,13 +127,7 @@ void FactorizationController::start(long long number) { | |||
|     emit progressChanged(); | ||||
|     emit factorsChanged(); | ||||
|     emit curFactNumberChanged(); | ||||
| 
 | ||||
|     if (m_useSqrtOptimization) { | ||||
|         // we could also just compute this every time, but sqrt is pretty expensive
 | ||||
|         m_stopFactor = static_cast<long long>(std::sqrt(m_currentFactNumber)); | ||||
|     } else { | ||||
|         m_stopFactor = m_currentFactNumber - 1; | ||||
|     } | ||||
|     emit stopFactorChanged(); | ||||
| 
 | ||||
|     m_timer.start(0); | ||||
| } | ||||
|  | @ -134,13 +167,17 @@ void FactorizationController::reset() { | |||
|         return; | ||||
| 
 | ||||
|     m_isPaused = false; | ||||
|     m_currentFactNumber = m_originalNumber; | ||||
|     m_currentFactor = 2; | ||||
|     m_originalNumber = 0; | ||||
|     m_currentFactNumber = 0; | ||||
|     m_currentFactor = 0; | ||||
|     m_stopFactor = 0; | ||||
|     m_factors.clear(); | ||||
|     emit isPausedChanged(); | ||||
|     emit currentFactorChanged(); | ||||
|     emit progressChanged(); | ||||
|     emit curFactNumberChanged(); | ||||
|     emit factorsChanged(); | ||||
|     emit stopFactorChanged(); | ||||
|     emit progressChanged(); | ||||
| } | ||||
| 
 | ||||
| void FactorizationController::onTimerTick() { | ||||
|  | @ -189,12 +226,16 @@ 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<long long>(std::sqrt(m_currentFactNumber)); | ||||
|             m_stopFactor = static_cast<unsigned long long>(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++; | ||||
|  |  | |||
|  | @ -26,11 +26,13 @@ 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(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<long long> factors READ factors NOTIFY factorsChanged) | ||||
|     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<unsigned long long> factors READ factors NOTIFY factorsChanged) | ||||
| 
 | ||||
|   public: | ||||
|     explicit FactorizationController(QObject* parent = nullptr); | ||||
|  | @ -41,7 +43,7 @@ class FactorizationController : public QObject { | |||
|      * @brief Gets the current progress of factorization. | ||||
|      * @return The progress percentage (0-100). | ||||
|      */ | ||||
|     int progress() const; | ||||
|     double progress() const; | ||||
| 
 | ||||
|     /**
 | ||||
|      * @brief Checks if the factorization process is running. | ||||
|  | @ -87,11 +89,17 @@ 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. | ||||
|      */ | ||||
|     long long number() const; | ||||
|     unsigned long long number() const; | ||||
| 
 | ||||
|     /**
 | ||||
|      * @brief The current number being factorized. | ||||
|  | @ -100,7 +108,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. | ||||
|      */ | ||||
|     long long curFactNumber() const; | ||||
|     unsigned long long curFactNumber() const; | ||||
| 
 | ||||
|     /**
 | ||||
|      * @brief Gets the current factor being tested. | ||||
|  | @ -110,7 +118,17 @@ class FactorizationController : public QObject { | |||
|      * is a factor, going one by one. This returns the current factor (to be checked in the | ||||
|      * next iteration). | ||||
|      */ | ||||
|     long long currentFactor() const; | ||||
|     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; | ||||
| 
 | ||||
|     /**
 | ||||
|      * @brief Gets the list of discovered factors (may not be complete). | ||||
|  | @ -120,7 +138,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<long long> factors() const; | ||||
|     QList<unsigned long long> factors() const; | ||||
| 
 | ||||
|     // endregion
 | ||||
|     // region: Setters
 | ||||
|  | @ -149,11 +167,20 @@ 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. | ||||
|      * | ||||
|      * Note that changing this value while the computation is in progress will reset the | ||||
|      * computation. | ||||
|      * 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). | ||||
|      */ | ||||
|     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
 | ||||
| 
 | ||||
|  | @ -164,7 +191,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(long long number); | ||||
|     Q_INVOKABLE void start(unsigned long long number); | ||||
| 
 | ||||
|     /**
 | ||||
|      * @brief Stops the ongoing factorization process. | ||||
|  | @ -197,12 +224,14 @@ 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(); | ||||
|  | @ -212,12 +241,13 @@ 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.
 | ||||
|     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<long long> m_factors; ///< List of discovered prime factors.
 | ||||
|     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<unsigned long long> m_factors; ///< List of discovered prime factors.
 | ||||
|     QTimer m_timer; ///< Timer for stepwise execution.
 | ||||
| 
 | ||||
|     /**
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue