Add iterations per cycle & optional sqrt optimization
This commit is contained in:
parent
e0178e27d2
commit
37234a44c9
3 changed files with 185 additions and 64 deletions
146
qml/Main.qml
146
qml/Main.qml
|
@ -15,55 +15,85 @@ ApplicationWindow {
|
|||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 10
|
||||
spacing: 15
|
||||
|
||||
Text {
|
||||
text: "Enter a number to factorize:"
|
||||
font.pixelSize: 16
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: numberInput
|
||||
placeholderText: "Enter number"
|
||||
// NOTE: We can't use the IntValidator here, since it doesn't support 64-bit values (long long)
|
||||
GroupBox {
|
||||
title: "Input"
|
||||
Layout.fillWidth: true
|
||||
onTextChanged: {
|
||||
// If the number changes, reset
|
||||
factorizationController.reset();
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 10
|
||||
ColumnLayout {
|
||||
spacing: 10
|
||||
|
||||
Button {
|
||||
text: {
|
||||
if (factorizationController.isPaused) {
|
||||
return "Resume";
|
||||
} else if (factorizationController.isRunning) {
|
||||
return "...";
|
||||
} else {
|
||||
return "Start";
|
||||
}
|
||||
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)
|
||||
Layout.fillWidth: true
|
||||
font.pixelSize: 16
|
||||
onTextChanged: factorizationController.reset()
|
||||
}
|
||||
Layout.fillWidth: true
|
||||
enabled: !factorizationController.isRunning
|
||||
onClicked: {
|
||||
if (factorizationController.isPaused) {
|
||||
factorizationController.resume();
|
||||
} else {
|
||||
factorizationController.start(parseInt(numberInput.text, 10));
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Button {
|
||||
text: factorizationController.isPaused ? "Resume" : factorizationController.isRunning ? "..." : "Start"
|
||||
Layout.fillWidth: true
|
||||
enabled: !factorizationController.isRunning
|
||||
onClicked: {
|
||||
if (factorizationController.isPaused) {
|
||||
factorizationController.resume();
|
||||
} else {
|
||||
factorizationController.start(parseInt(numberInput.text, 10));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Pause"
|
||||
Layout.fillWidth: true
|
||||
enabled: factorizationController.isRunning
|
||||
onClicked: factorizationController.stop()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Pause"
|
||||
Layout.fillWidth: true
|
||||
enabled: factorizationController.isRunning
|
||||
onClicked: factorizationController.stop()
|
||||
GroupBox {
|
||||
title: "Settings"
|
||||
Layout.fillWidth: true
|
||||
ColumnLayout {
|
||||
spacing: 10
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
|
||||
Text {
|
||||
text: "Iterations per cycle:"
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
}
|
||||
|
||||
Slider {
|
||||
id: iterationSlider
|
||||
Layout.fillWidth: true
|
||||
from: 1
|
||||
to: 100000
|
||||
stepSize: 1
|
||||
value: 1
|
||||
onValueChanged: factorizationController.iterationsPerCycle = value
|
||||
}
|
||||
|
||||
Text {
|
||||
text: iterationSlider.value.toFixed(0)
|
||||
font.bold: true
|
||||
Layout.alignment: Qt.AlignRight
|
||||
}
|
||||
}
|
||||
|
||||
CheckBox {
|
||||
text: "Stop at sqrt(n)"
|
||||
checked: true
|
||||
onCheckedChanged: factorizationController.useSqrtOptimization = checked
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,32 +104,34 @@ ApplicationWindow {
|
|||
value: factorizationController.progress
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "Current Factor: " + factorizationController.currentFactor
|
||||
font.pixelSize: 14
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
GroupBox {
|
||||
title: "Current Status"
|
||||
Layout.fillWidth: true
|
||||
ColumnLayout {
|
||||
spacing: 5
|
||||
|
||||
Text {
|
||||
text: "Current Factor: " + factorizationController.currentFactor
|
||||
font.pixelSize: 14
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "Factors Found:"
|
||||
font.pixelSize: 14
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
|
||||
ListView {
|
||||
GroupBox {
|
||||
title: "Factors Found"
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
model: factorizationController.factors
|
||||
delegate: Text {
|
||||
text: modelData
|
||||
|
||||
Text {
|
||||
text: factorizationController.factors.join(", ")
|
||||
font.pixelSize: 14
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
width: parent.width
|
||||
color: "black"
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "Warning: This only shows factors below sqrt(num)"
|
||||
text: factorizationController.useSqrtOptimization ? "Note: Only factors up to sqrt(n) are shown." : "Note: Finding all factors (slower)."
|
||||
font.pixelSize: 12
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
#include <cassert>
|
||||
#include <cmath>
|
||||
|
||||
FactorizationController::FactorizationController(QObject* parent) : QObject{parent}, m_isRunning(false), m_currentFactNumber(0), m_currentFactor(2) {
|
||||
FactorizationController::FactorizationController(QObject* parent) :
|
||||
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));
|
||||
}
|
||||
|
||||
|
@ -36,6 +37,31 @@ bool FactorizationController::isPaused() const {
|
|||
return m_isPaused;
|
||||
}
|
||||
|
||||
bool FactorizationController::useSqrtOptimization() const {
|
||||
return m_useSqrtOptimization;
|
||||
}
|
||||
|
||||
void FactorizationController::setUseSqrtOptimization(bool value) {
|
||||
if (value == m_useSqrtOptimization)
|
||||
return;
|
||||
|
||||
m_useSqrtOptimization = value;
|
||||
emit useSqrtOptimizationChanged();
|
||||
reset();
|
||||
}
|
||||
|
||||
int FactorizationController::iterationsPerCycle() const {
|
||||
return m_iterationsPerCycle;
|
||||
}
|
||||
|
||||
void FactorizationController::setIterationsPerCycle(int number) {
|
||||
if (number == m_iterationsPerCycle)
|
||||
return;
|
||||
|
||||
m_iterationsPerCycle = number;
|
||||
emit iterationsPerCycleChanged();
|
||||
}
|
||||
|
||||
long long FactorizationController::currentFactor() const {
|
||||
return m_currentFactor;
|
||||
}
|
||||
|
@ -48,8 +74,6 @@ void FactorizationController::start(long long number) {
|
|||
m_originalNumber = number;
|
||||
m_currentFactNumber = number;
|
||||
m_currentFactor = 2;
|
||||
// we could also just compute this every time, but sqrt is pretty expensive
|
||||
m_stopFactor = static_cast<long long>(std::sqrt(m_currentFactNumber));
|
||||
m_isRunning = true;
|
||||
m_isFinished = false;
|
||||
m_factors.clear();
|
||||
|
@ -60,6 +84,13 @@ void FactorizationController::start(long long number) {
|
|||
emit progressChanged();
|
||||
emit factorsChanged();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
m_timer.start(0);
|
||||
}
|
||||
|
||||
|
@ -108,7 +139,12 @@ void FactorizationController::reset() {
|
|||
}
|
||||
|
||||
void FactorizationController::onTimerTick() {
|
||||
factorize();
|
||||
for (int i = 0; i < m_iterationsPerCycle; i++) {
|
||||
if (!m_isRunning)
|
||||
break;
|
||||
|
||||
factorize();
|
||||
}
|
||||
}
|
||||
|
||||
void FactorizationController::factorize() {
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
#include <QVariant>
|
||||
#include <qqmlintegration.h>
|
||||
#include <qtmetamacros.h>
|
||||
|
||||
|
@ -11,8 +12,11 @@
|
|||
* @brief A class that performs integer factorization in a step-by-step manner.
|
||||
*
|
||||
* This class uses a timer to progressively factorize a given number, allowing
|
||||
* for real-time updates on progress and discovered factors. It is designed
|
||||
* to be used in a Qt-based QML application.
|
||||
* for real-time updates on progress and discovered factors. The computation will
|
||||
* run in a single thread, utilizing 0 tick timers to perform a small number of
|
||||
* iterations on each cycle of the event loop.
|
||||
*
|
||||
* It is designed to be used in a Qt-based QML application.
|
||||
*/
|
||||
class FactorizationController : public QObject {
|
||||
Q_OBJECT
|
||||
|
@ -20,6 +24,8 @@ class FactorizationController : public QObject {
|
|||
Q_PROPERTY(bool isRunning READ isRunning NOTIFY isRunningChanged)
|
||||
Q_PROPERTY(bool isFinished READ isFinished NOTIFY isFinishedChanged)
|
||||
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 currentFactor READ currentFactor NOTIFY currentFactorChanged)
|
||||
Q_PROPERTY(int progress READ progress NOTIFY progressChanged)
|
||||
|
@ -68,6 +74,18 @@ class FactorizationController : public QObject {
|
|||
*/
|
||||
bool isPaused() const;
|
||||
|
||||
/**
|
||||
* @brief Gets the number of iterations to be performed per cycle.
|
||||
* @return The number of iterations performed per cycle.
|
||||
*/
|
||||
int iterationsPerCycle() const;
|
||||
|
||||
/**
|
||||
* @brief Checks whether sqrt optimization is enabled.
|
||||
* @return True if the sqrt optimization is enabled, otherwise False.
|
||||
*/
|
||||
bool useSqrtOptimization() const;
|
||||
|
||||
/**
|
||||
* @brief Gets the original number being factorized.
|
||||
* @return The number being factorized.
|
||||
|
@ -94,6 +112,37 @@ class FactorizationController : public QObject {
|
|||
*/
|
||||
QList<long long> factors() const;
|
||||
|
||||
// endregion
|
||||
// region: Setters
|
||||
|
||||
/**
|
||||
* @brief Set the number of iterations per cycle.
|
||||
*
|
||||
* This is a way to speed up the computation, by increasing the amount of iterations
|
||||
* performed per each computation (on every event loop cycle). Setting this to a number
|
||||
* too high might lead to OS thinking the application is not responding, and the UI
|
||||
* feeling slow. The optimal number depends on the speed of the CPU and the allocated
|
||||
* CPU time to this process.
|
||||
*
|
||||
* This value can be changed even as a computation is ongoing.
|
||||
*/
|
||||
void setIterationsPerCycle(int number);
|
||||
|
||||
/**
|
||||
* @brief Enable or disable using sqrt optimizations.
|
||||
*
|
||||
* When sqrt optimization is enabled, only factors up to sqrt of the original number
|
||||
* will be checked. This allows the algorithm to finish quicker.
|
||||
*
|
||||
* If the intention is purely to check whether number is or isn't prime, this optimization
|
||||
* is very useful. However, enabling it will lead to some factors not being found, so if
|
||||
* you wish to perform a full factorization, leave this turned off.
|
||||
*
|
||||
* Note that changing this value while the computation is in progress will reset the
|
||||
* computation.
|
||||
*/
|
||||
void setUseSqrtOptimization(bool value);
|
||||
|
||||
// endregion
|
||||
// region: Functions
|
||||
|
||||
|
@ -135,11 +184,13 @@ class FactorizationController : public QObject {
|
|||
signals:
|
||||
void isRunningChanged();
|
||||
void isFinishedChanged();
|
||||
void isPausedChanged();
|
||||
void useSqrtOptimizationChanged();
|
||||
void iterationsPerCycleChanged();
|
||||
void numberChanged();
|
||||
void currentFactorChanged();
|
||||
void factorsChanged();
|
||||
void progressChanged();
|
||||
void isPausedChanged();
|
||||
|
||||
private slots:
|
||||
void onTimerTick();
|
||||
|
@ -148,6 +199,8 @@ class FactorizationController : public QObject {
|
|||
bool m_isRunning; ///< Indicates whether factorization is active.
|
||||
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
|
||||
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.
|
||||
|
|
Loading…
Add table
Reference in a new issue