Commit 710381b8 authored by Rohan Asokan's avatar Rohan Asokan
Browse files
parents cfd4f515 898d1c64
......@@ -8,6 +8,7 @@ Originally starting as a fork of [Liri calculator](https://github.com/lirios/cal
* History
* Unit conversion
* Currency conversion
* Binary calculation
## Links
* Project page: https://invent.kde.org/plasma-mobile/kalk
......@@ -16,6 +17,7 @@ Originally starting as a fork of [Liri calculator](https://github.com/lirios/cal
## Dependencies
* Qt5
* Qt5 Feedback
* Cmake
* KI18n
* KUnitConversion
......@@ -23,6 +25,8 @@ Originally starting as a fork of [Liri calculator](https://github.com/lirios/cal
* KConfig
* GNU Bison
* Flex
* GMP
* MPFR
## Building and Installing
......
......@@ -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;
......
/*
* SPDX-FileCopyrightText: 2021-2022 Rohan Asokan <rohan.asokan@students.iiit.ac.in>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "knumber_binary_wrapper.h"
#include "knumber.h"
#include <QString>
#include <QRegularExpression>
#include <QLatin1String>
#include <QDebug>
// Constructors and Destructors
BinaryNumber::BinaryNumber(const BinaryNumber& other) {
m_number = other.toKNum();
}
BinaryNumber::BinaryNumber(const KNumber &num) {
m_number = num;
}
BinaryNumber::BinaryNumber(const QString &s) : m_number(KNumber("UNDEFINED_ERROR")) {
const QRegularExpression binary_regex("^[01]+.[01]+|^[01]+");
if (binary_regex.match(s).hasMatch()) {
m_number = KNumber(0);
int seperator_loc = s.indexOf('.');
if (seperator_loc == -1) seperator_loc = s.length();
KNumber multiplier(1);
KNumber base(2);
// Integer Part Calculations
for (int idx = seperator_loc - 1; idx >= 0; idx--) {
m_number += (KNumber(s.at(idx)) * multiplier);
multiplier *= base;
}
// multiplier = base;
// // Fractional Part Calculations
// for (int idx = seperator_loc + 1; idx < s.length(); idx++) {
// m_number += (KNumber(s.at(idx)) / base);
// multiplier *= base;
// }
}
}
// Converters
QString BinaryNumber::toDec() const {
return m_number.toQString();
}
KNumber BinaryNumber::toKNum() const {
return m_number;
}
// Operators
BinaryNumber &BinaryNumber::operator=(const BinaryNumber &rhs) {
(*this).m_number = rhs.toKNum();
return *this;
}
BinaryNumber operator+(const BinaryNumber &lhs, const BinaryNumber &rhs) {
KNumber res(lhs.toKNum());
res += rhs.toKNum();
return BinaryNumber(res);
}
BinaryNumber operator-(const BinaryNumber &lhs, const BinaryNumber &rhs) {
KNumber res(lhs.toKNum());
res -= rhs.toKNum();
return BinaryNumber(res);
}
BinaryNumber operator*(const BinaryNumber &lhs, const BinaryNumber &rhs) {
KNumber res(lhs.toKNum());
res *= rhs.toKNum();
return BinaryNumber(res);
}
BinaryNumber operator/(const BinaryNumber &lhs, const BinaryNumber &rhs) {
KNumber res(lhs.toKNum());
res /= rhs.toKNum();
return BinaryNumber(res);
}
BinaryNumber operator&(const BinaryNumber &lhs, const BinaryNumber &rhs) {
KNumber res(lhs.toKNum());
res &= rhs.toKNum();
return BinaryNumber(res);
}
BinaryNumber operator|(const BinaryNumber &lhs, const BinaryNumber &rhs) {
KNumber res(lhs.toKNum());
res |= rhs.toKNum();
return BinaryNumber(res);
}
BinaryNumber operator^(const BinaryNumber &lhs, const BinaryNumber &rhs) {
KNumber res(lhs.toKNum());
res ^= rhs.toKNum();
return BinaryNumber(res);
}
BinaryNumber operator<<(const BinaryNumber &lhs, const BinaryNumber &rhs) {
KNumber res(lhs.toKNum());
res <<= rhs.toKNum();
return BinaryNumber(res);
}
BinaryNumber operator>>(const BinaryNumber &lhs, const BinaryNumber &rhs) {
KNumber res(lhs.toKNum());
res >>= rhs.toKNum();
return BinaryNumber(res);
}
/*
* SPDX-FileCopyrightText: 2021-2022 Rohan Asokan <rohan.asokan@students.iiit.ac.in>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include <QString>
#include "knumber.h"
class BinaryNumber {
public:
// construction/destruction
BinaryNumber();
explicit BinaryNumber(const QString &s);
explicit BinaryNumber(const KNumber &num);
BinaryNumber(const BinaryNumber &other);
// ~BinaryNumber();
public:
// assignment
BinaryNumber &operator=(const BinaryNumber &rhs);
public:
// Unary operators
// KNumber &operator~();
public:
// Converters
QString toHex() const;
QString toOct() const;
QString toBin() const;
QString toDec() const;
KNumber toKNum() const;
private:
KNumber m_number;
};
BinaryNumber operator+(const BinaryNumber &lhs, const BinaryNumber &rhs);
BinaryNumber operator-(const BinaryNumber &lhs, const BinaryNumber &rhs);
BinaryNumber operator*(const BinaryNumber &lhs, const BinaryNumber &rhs);
BinaryNumber operator/(const BinaryNumber &lhs, const BinaryNumber &rhs);
BinaryNumber operator&(const BinaryNumber &lhs, const BinaryNumber &rhs);
BinaryNumber operator|(const BinaryNumber &lhs, const BinaryNumber &rhs);
BinaryNumber operator^(const BinaryNumber &lhs, const BinaryNumber &rhs);
BinaryNumber operator<<(const BinaryNumber &lhs, const BinaryNumber &rhs);
BinaryNumber operator>>(const BinaryNumber &lhs, const BinaryNumber &rhs);
......@@ -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);
......
......@@ -7,6 +7,10 @@
<file>qml/CalculationPage.qml</file>
<file>qml/FunctionPad.qml</file>
<file>qml/AboutPage.qml</file>
<file>qml/BinaryCalculator.qml</file>
<file>qml/BinaryPad.qml</file>
<file>qml/UnitConverter.qml</file>
<file>qml/PortraitPad.qml</file>
<file>qml/LandScapePad.qml</file>
</qresource>
</RCC>
/*
* SPDX-FileCopyrightText: 2020-2021 Han Young <hanyoung@protonmail.com>
* SPDX-FileCopyrightText: 2021-2022 Rohan Asokan <rohan.asokan@students.iiit.ac.in>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "inputmanager.h"
#include "mathengine.h"
#include "historymanager.h"
#include <QDebug>
InputManager::InputManager()
{
}
......@@ -43,7 +45,14 @@ void InputManager::append(const QString &subexpression)
}
m_moveFromResult = false;
MathEngine::inst()->parse(m_expression + subexpression);
// Call the corresponding parser based on the type of expression.
MathEngine * engineInstance = MathEngine::inst();
if (m_isBinaryMode) {
engineInstance->parseBinaryExpression(m_expression + subexpression);
} else {
engineInstance->parse(m_expression + subexpression);
}
if(!MathEngine::inst()->error())
{
m_stack.push_back(subexpression.size());
......@@ -60,7 +69,15 @@ void InputManager::backspace()
{
m_expression.chop(m_stack.back());
Q_EMIT expressionChanged();
MathEngine::inst()->parse(m_expression);
// Call the corresponding parser based on the type of expression.
MathEngine * engineInstance = MathEngine::inst();
if (m_isBinaryMode) {
engineInstance->parseBinaryExpression(m_expression);
} else {
engineInstance->parse(m_expression);
}
if(!MathEngine::inst()->error())
{
m_result = MathEngine::inst()->result();
......@@ -102,3 +119,8 @@ void InputManager::fromHistory(const QString &result)
Q_EMIT expressionChanged();
Q_EMIT resultChanged();
}
void InputManager::setBinaryMode(bool active) {
m_isBinaryMode = active;
clear();
}
/*
* SPDX-FileCopyrightText: 2020-2021 Han Young <hanyoung@protonmail.com>
* SPDX-FileCopyrightText: 2021-2022 Rohan Asokan <rohan.asokan@Students.iiit.ac.in>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
......@@ -22,6 +23,7 @@ public:
Q_INVOKABLE void equal();
Q_INVOKABLE void clear();
Q_INVOKABLE void fromHistory(const QString &result);
Q_INVOKABLE void setBinaryMode(bool active);
Q_SIGNALS:
void expressionChanged();
void resultChanged();
......@@ -31,5 +33,6 @@ private:
std::vector<int> m_stack; // track subexpression length for removal later
QString m_expression;
QString m_result;
bool m_isBinaryMode = false; // Changes the parser based on this variable
};
/*
* SPDX-FileCopyrightText: 2020-2021 Han Young <hanyoung@protonmail.com>
* SPDX-FileCopyrightText: 2021-2022 Rohan Asokan
* <rohan.asokan@students.iiit.ac.in>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "mathengine.h"
#include <QDebug>
#include <QRegularExpression>
#include <QStringList>
#include <knumber.h>
void MathEngine::parse(QString expr)
{
m_driver.parse(expr.toStdString());
m_result = QString::number(m_driver.result);
void MathEngine::parse(QString expr) {
m_driver.parse(expr.toStdString());
m_result = m_driver.result;
emit resultChanged();
}
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;
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 = KNumber::binaryFromString(numbers[0]).toBinaryString(0);
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]);