Commit 94d41ca4 authored by Han Young's avatar Han Young
Browse files

extend KNumber to include binary i/o

parent de1c8d51
......@@ -5,7 +5,6 @@ add_library(knumber STATIC
knumber_fraction.cpp
knumber_integer.cpp
knumber_operators.cpp
knumber_binary_wrapper.cpp
)
target_include_directories(knumber PUBLIC ${CMAKE_BINARY_DIR} ${GMP_INCLUDE_DIR})
......
......@@ -26,6 +26,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <QRegExp>
#include <QStringList>
#include <cmath>
#include <QDebug>
QString KNumber::GroupSeparator = QStringLiteral(",");
QString KNumber::DecimalSeparator = QStringLiteral(".");
......@@ -268,7 +269,13 @@ KNumber KNumber::Euler() {
//------------------------------------------------------------------------------
KNumber::KNumber() : value_(new detail::knumber_integer(0)) {
}
KNumber KNumber::binaryFromString(const QString &s)
{
KNumber instance(0);
delete instance.value_;
instance.value_ = detail::knumber_integer::binaryFromString(s);
return instance;
}
//------------------------------------------------------------------------------
// Name: KNumber
//------------------------------------------------------------------------------
......@@ -630,6 +637,11 @@ QString KNumber::toQString(int width, int precision) const {
}
}
QString KNumber::toBinaryString(int precision) const
{
return value_->toBinaryString(precision);
}
//------------------------------------------------------------------------------
// Name: toUint64
//------------------------------------------------------------------------------
......
......@@ -58,9 +58,9 @@ public:
public:
// construction/destruction
static KNumber binaryFromString(const QString &s);
KNumber();
explicit KNumber(const QString &s);
explicit KNumber(qint32 value);
explicit KNumber(qint64 value);
explicit KNumber(quint32 value);
......@@ -110,6 +110,7 @@ public:
public:
QString toQString(int width = -1, int precision = -1) const;
QString toBinaryString(int precision) const;
quint64 toUint64() const;
qint64 toInt64() const;
......
......@@ -42,6 +42,7 @@ public:
public:
virtual QString toString(int precision) const = 0;
virtual QString toBinaryString(int precision) const = 0;
virtual quint64 toUint64() const = 0;
virtual qint64 toInt64() const = 0;
......
......@@ -98,7 +98,20 @@ QString knumber_error::toString(int precision) const {
return QStringLiteral("nan");
}
}
QString knumber_error::toBinaryString(int precision) const {
Q_UNUSED(precision);
switch(error_) {
case ERROR_POS_INFINITY:
return QStringLiteral("inf");
case ERROR_NEG_INFINITY:
return QStringLiteral("-inf");
case ERROR_UNDEFINED:
default:
return QStringLiteral("nan");
}
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
......
......@@ -46,6 +46,7 @@ public:
public:
QString toString(int precision) const override;
QString toBinaryString(int precision) const override;
quint64 toUint64() const override;
qint64 toInt64() const override;
......
......@@ -592,6 +592,26 @@ QString knumber_float::toString(int precision) const {
return QLatin1String(&buf[0]);
}
QString knumber_float::toBinaryString(int precision) const {
size_t size;
if (precision > 0) {
size = static_cast<size_t>(mpfr_snprintf(nullptr, 0, "%.*Rb", precision, mpfr_) + 1);
} else {
size = static_cast<size_t>(mpfr_snprintf(nullptr, 0, "%.Rb", mpfr_) + 1);
}
QScopedArrayPointer<char> buf(new char[size]);
if (precision > 0) {
mpfr_snprintf(&buf[0], size, "%.*Rb", precision, mpfr_);
} else {
mpfr_snprintf(&buf[0], size, "%.Rb", mpfr_);
}
return QLatin1String(&buf[0]);
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
......
......@@ -55,6 +55,7 @@ private:
public:
QString toString(int precision) const override;
QString toBinaryString(int precision) const override;
quint64 toUint64() const override;
qint64 toInt64() const override;
......
......@@ -777,7 +777,54 @@ QString knumber_fraction::toString(int precision) const {
return knumber_float(this).toString(precision);
}
}
QString knumber_fraction::toBinaryString(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, "%Zb %Zb/%Zb", integer_part_1.mpz_, num, mpq_denref(mpq_)) + 1;
QScopedArrayPointer<char> buf(new char[size]);
gmp_snprintf(&buf[0], size, "%Zb %Zb/%Zb", 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, "%Zb/%Zb", num, mpq_denref(mpq_)) + 1;
QScopedArrayPointer<char> buf(new char[size]);
gmp_snprintf(&buf[0], size, "%Zb/%Zb", num, mpq_denref(mpq_));
mpz_clear(num);
return QLatin1String(&buf[0]);
}
} else {
return knumber_float(this).toString(precision);
}
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
......
......@@ -53,6 +53,7 @@ public:
public:
QString toString(int precision) const override;
QString toBinaryString(int precision) const override;
quint64 toUint64() const override;
qint64 toInt64() const override;
......
......@@ -22,9 +22,18 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "knumber_fraction.h"
#include "knumber_error.h"
#include <QScopedArrayPointer>
#include <QRegularExpression>
namespace detail {
knumber_integer *knumber_integer::binaryFromString(const QString &s)
{
auto instance = new knumber_integer(0);
const QRegularExpression binary_regex("^[01]+.[01]+|^[01]+");
if (binary_regex.match(s).hasMatch()) {
mpz_set_str(instance->mpz_, s.toLatin1().constData(), 2);
}
return instance;
}
//------------------------------------------------------------------------------
// Name: knumber_integer
//------------------------------------------------------------------------------
......@@ -707,7 +716,11 @@ QString knumber_integer::toString(int precision) const {
gmp_snprintf(&buf[0], size, "%Zd", mpz_);
return QLatin1String(&buf[0]);
}
QString knumber_integer::toBinaryString(int precision) const
{
Q_UNUSED(precision);
return QString::fromLatin1(mpz_get_str(NULL, 2, mpz_));
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
......
......@@ -20,7 +20,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define KNUMBER_INTEGER_H_
#include "knumber_base.h"
class BinaryNumber;
class KNumber;
namespace detail {
......@@ -32,6 +32,7 @@ class knumber_integer : public knumber_base {
friend class knumber_float;
public:
static knumber_integer *binaryFromString(const QString &s);
explicit knumber_integer(const QString &s);
explicit knumber_integer(qint32 value);
explicit knumber_integer(qint64 value);
......@@ -45,6 +46,7 @@ public:
public:
QString toString(int precision) const override;
QString toBinaryString(int precision) const override;
quint64 toUint64() const override;
qint64 toInt64() const override;
......@@ -106,7 +108,8 @@ public:
public:
int compare(knumber_base *rhs) override;
protected:
mpz_t &mpz();
private:
// conversion constructors
explicit knumber_integer(const knumber_integer *value);
......
/*
* SPDX-FileCopyrightText: 2020-2021 Han Young <hanyoung@protonmail.com>
* SPDX-FileCopyrightText: 2021-2022 Rohan Asokan <rohan.asokan@students.iiit.ac.in>
* SPDX-FileCopyrightText: 2021-2022 Rohan Asokan
* <rohan.asokan@students.iiit.ac.in>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
......@@ -8,90 +9,97 @@
#include <QDebug>
#include <QRegularExpression>
#include <QStringList>
#include "knumber_binary_wrapper.h"
#include <knumber.h>
void MathEngine::parse(QString expr)
{
m_driver.parse(expr.toStdString());
m_result = QString::number(m_driver.result);
emit resultChanged();
void MathEngine::parse(QString expr) {
m_driver.parse(expr.toStdString());
m_result = QString::number(m_driver.result);
emit resultChanged();
}
QStringList getRegexMatches(QString expr, QString regex, int *counter) {
QRegularExpression re(regex);
QRegularExpressionMatch regexMatch;
QRegularExpressionMatchIterator it = re.globalMatch(expr);
QStringList matches;
while (it.hasNext()) {
regexMatch = it.next();
QString match = regexMatch.captured(0);
matches << match;
(*counter)++;
}
return matches;
QStringList MathEngine::getRegexMatches(const QString &expr,
const QString &regex,
int *counter) const {
QRegularExpression re(regex);
QRegularExpressionMatch regexMatch;
QRegularExpressionMatchIterator it = re.globalMatch(expr);
QStringList matches;
while (it.hasNext()) {
regexMatch = it.next();
QString match = regexMatch.captured(0);
matches << match;
(*counter)++;
}
return matches;
}
void MathEngine::parseBinaryExpression(QString expr)
{
m_error = true;
qDebug() << "Current Epxression (mathengine.cpp): " << expr;
void MathEngine::parseBinaryExpression(QString expr) {
m_error = true;
qDebug() << "Current Epxression (mathengine.cpp): " << expr;
int numbersPresent = 0;
int operatorsPresent = 0;
// Match for the numbers and binary operators
QStringList numbers = getRegexMatches(expr, bitRegex, &numbersPresent);
QStringList operators = getRegexMatches(expr, binaryOperatorRegex, &operatorsPresent);
int numbersPresent = 0;
int operatorsPresent = 0;
// Match for the numbers and binary operators
QStringList numbers = getRegexMatches(expr, bitRegex, &numbersPresent);
QStringList operators =
getRegexMatches(expr, binaryOperatorRegex, &operatorsPresent);
// Erroraneous Parses return here itself
if (
(operatorsPresent != 0 && numbersPresent == 0) ||
(operatorsPresent > 1) ||
(numbersPresent > 2)
) {
return;
} else {
m_error = false;
if (operatorsPresent == 0 && numbersPresent == 1) {
m_result = BinaryNumber(numbers[0]).toDec();
emit resultChanged();
}
// Erroraneous Parses return here itself
if ((operatorsPresent != 0 && numbersPresent == 0) ||
(operatorsPresent > 1) || (numbersPresent > 2)) {
return;
} else {
m_error = false;
if (operatorsPresent == 0 && numbersPresent == 1) {
m_result = KNumber::binaryFromString(numbers[0]).toBinaryString(0);
emit resultChanged();
}
}
// Binary Operator Syntax
if (expressionSyntaxRegex1.match(expr).hasMatch()) {
BinaryNumber result(0);
switch (operatorsList.indexOf(operators[0])) {
case 0: // +
result = BinaryNumber(numbers[0]) + BinaryNumber(numbers[1]);
break;
case 1: // -
result = BinaryNumber(numbers[0]) - BinaryNumber(numbers[1]);
break;
case 2: // *
result = BinaryNumber(numbers[0]) * BinaryNumber(numbers[1]);
break;
case 3: // /
result = BinaryNumber(numbers[0]) / BinaryNumber(numbers[1]);
break;
case 4: // &
result = BinaryNumber(numbers[0]) & BinaryNumber(numbers[1]);
break;
case 5: // |
result = BinaryNumber(numbers[0]) | BinaryNumber(numbers[1]);
break;
case 6: // ^
result = BinaryNumber(numbers[0]) ^ BinaryNumber(numbers[1]);
break;
case 7: // <<
result = BinaryNumber(numbers[0]) << BinaryNumber(numbers[1]);
break;
case 8: // >>
result = BinaryNumber(numbers[0]) >> BinaryNumber(numbers[1]);
break;
default: // error
m_error = true;
};
m_result = result.toDec();
emit resultChanged();
}
// Binary Operator Syntax
if (expressionSyntaxRegex1.match(expr).hasMatch()) {
KNumber result(0);
switch (operatorsList.indexOf(operators[0])) {
case 0: // +
result = KNumber::binaryFromString(numbers[0]) +
KNumber::binaryFromString(numbers[1]);
break;
case 1: // -
result = KNumber::binaryFromString(numbers[0]) -
KNumber::binaryFromString(numbers[1]);
break;
case 2: // *
result = KNumber::binaryFromString(numbers[0]) *
KNumber::binaryFromString(numbers[1]);
break;
case 3: // /
result = KNumber::binaryFromString(numbers[0]) /
KNumber::binaryFromString(numbers[1]);
break;
case 4: // &
result = KNumber::binaryFromString(numbers[0]) &
KNumber::binaryFromString(numbers[1]);
break;
case 5: // |
result = KNumber::binaryFromString(numbers[0]) |
KNumber::binaryFromString(numbers[1]);
break;
case 6: // ^
result = KNumber::binaryFromString(numbers[0]) ^
KNumber::binaryFromString(numbers[1]);
break;
case 7: // <<
result = KNumber::binaryFromString(numbers[0])
<< KNumber::binaryFromString(numbers[1]);
break;
case 8: // >>
result = KNumber::binaryFromString(numbers[0]) >>
KNumber::binaryFromString(numbers[1]);
break;
default: // error
m_error = true;
};
m_result = result.toBinaryString(0);
emit resultChanged();
}
}
/*
* SPDX-FileCopyrightText: 2020-2021 Han Young <hanyoung@protonmail.com>
* SPDX-FileCopyrightText: 2021-2022 Rohan Asokan <rohan.asokan@students.iiit.ac.in>
* SPDX-FileCopyrightText: 2021-2022 Rohan Asokan
* <rohan.asokan@students.iiit.ac.in>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
......@@ -10,43 +11,35 @@
#include <QObject>
#include <QRegularExpression>
#include <QStringList>
class MathEngine : public QObject
{
Q_OBJECT
Q_PROPERTY(QString result READ result NOTIFY resultChanged)
Q_PROPERTY(bool error READ error NOTIFY resultChanged)
class MathEngine : public QObject {
Q_OBJECT
Q_PROPERTY(QString result READ result NOTIFY resultChanged)
Q_PROPERTY(bool error READ error NOTIFY resultChanged)
public:
static MathEngine *inst()
{
static MathEngine singleton;
return &singleton;
}
Q_INVOKABLE void parse(QString expr);
Q_INVOKABLE void parseBinaryExpression(QString expr);
QString result()
{
return m_result;
};
bool error()
{
return m_driver.syntaxError || m_error;
};
static MathEngine *inst() {
static MathEngine singleton;
return &singleton;
}
Q_INVOKABLE void parse(QString expr);
Q_INVOKABLE void parseBinaryExpression(QString expr);
QString result() { return m_result; };
bool error() { return m_driver.syntaxError || m_error; };
signals:
void resultChanged();
void resultChanged();
private:
MathEngine(){};
driver m_driver;
QString m_result;
bool m_error;
const QString bitRegex = QString("[01]+");
const QString binaryOperatorRegex = QString("[\\+\\-\\*\\/&\\|\\^]|<{2}|>{2}");
QRegularExpression expressionSyntaxRegex1 = QRegularExpression("([01]+)([\\+\\-\\*\\/&\\|~\\^]|<{2}|>{2})([01]+)");
QStringList operatorsList = {
"+", "-", "*", "/",
"&", "|", "^",
"<<", ">>"
};
MathEngine(){};
driver m_driver;
QString m_result;
bool m_error;
const QString bitRegex = QString("[01]+");
const QString binaryOperatorRegex =
QString("[\\+\\-\\*\\/&\\|\\^]|<{2}|>{2}");
QRegularExpression expressionSyntaxRegex1 =
QRegularExpression("([01]+)([\\+\\-\\*\\/&\\|~\\^]|<{2}|>{2})([01]+)");
QStringList operatorsList = {"+", "-", "*", "/", "&", "|", "^", "<<", ">>"};
QStringList getRegexMatches(const QString &expr, const QString &regex,
int *counter) const;
};
#endif
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment