diff --git a/CMakeLists.txt b/CMakeLists.txt
index bdd1769..f88bcb6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,140 +1,148 @@
cmake_minimum_required(VERSION 3.5)
# KDE Application Version, managed by release script
set (KDE_APPLICATIONS_VERSION_MAJOR "19")
set (KDE_APPLICATIONS_VERSION_MINOR "07")
set (KDE_APPLICATIONS_VERSION_MICRO "70")
set (KDE_APPLICATIONS_VERSION "${KDE_APPLICATIONS_VERSION_MAJOR}.${KDE_APPLICATIONS_VERSION_MINOR}.${KDE_APPLICATIONS_VERSION_MICRO}")
project(kcalc VERSION ${KDE_APPLICATIONS_VERSION})
set(QT_MIN_VERSION "5.9.0")
set(KF5_MIN_VERSION "5.46.0")
find_package (ECM ${KF5_MIN_VERSION} REQUIRED NO_MODULE)
set (CMAKE_MODULE_PATH ${ECM_MODULE_PATH})
include(KDEInstallDirs)
include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE)
include(KDECMakeSettings)
include(ECMMarkAsTest)
include(FeatureSummary)
include(ECMAddAppIcon)
include(ECMSetupVersion)
## Generate header with version number
ecm_setup_version(${KDE_APPLICATIONS_VERSION} VARIABLE_PREFIX KCALC
VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/kcalc_version.h"
)
find_package (Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS
Core
Widgets
)
find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS
Crash
Config
ConfigWidgets
DocTools
GuiAddons
I18n
Init
Notifications
XmlGui
)
add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x060000)
set (CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" ${CMAKE_SOURCE_DIR}/cmake/modules)
kde_enable_exceptions()
find_package(GMP)
set_package_properties(GMP PROPERTIES
DESCRIPTION "The GNU Multiple Precision Arithmetic Library"
URL "https://gmplib.org/"
TYPE REQUIRED
PURPOSE "Required for building KCalc."
)
+find_package(MPFR)
+set_package_properties(MPFR PROPERTIES
+ DESCRIPTION "The GNU Multiple Precision Floating-Point Reliable Library"
+ URL "https://www.mpfr.org/"
+ TYPE REQUIRED
+ PURPOSE "Required for building KCalc."
+)
+
include(CheckTypeSize)
include(CheckIncludeFiles)
check_include_files(ieeefp.h HAVE_IEEEFP_H)
check_type_size("signed long" SIZEOF_SIGNED_LONG)
check_type_size("unsigned long" SIZEOF_UNSIGNED_LONG)
configure_file(config-kcalc.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-kcalc.h )
include_directories( ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/knumber ${GMP_INCLUDE_DIR} )
########### next target ###############
# Needs absolute paths due to the test program for knumber
set(libknumber_la_SRCS
${kcalc_SOURCE_DIR}/knumber/knumber.cpp
${kcalc_SOURCE_DIR}/knumber/knumber_error.cpp
${kcalc_SOURCE_DIR}/knumber/knumber_float.cpp
${kcalc_SOURCE_DIR}/knumber/knumber_fraction.cpp
${kcalc_SOURCE_DIR}/knumber/knumber_integer.cpp
${kcalc_SOURCE_DIR}/knumber/knumber_operators.cpp
)
add_subdirectory( knumber )
# add_subdirectory( tests )
set(kcalc_KDEINIT_SRCS ${libknumber_la_SRCS}
kcalc.cpp
bitbutton.cpp
kcalc_bitset.cpp
kcalc_button.cpp
kcalc_const_button.cpp
kcalc_const_menu.cpp
kcalc_core.cpp
kcalcdisplay.cpp
kcalc_statusbar.cpp
stats.cpp )
ki18n_wrap_ui(kcalc_KDEINIT_SRCS
kcalc.ui
constants.ui
colors.ui
fonts.ui
general.ui)
kconfig_add_kcfg_files(kcalc_KDEINIT_SRCS kcalc_settings.kcfgc )
# Sets the icon on Windows and OSX
file(GLOB ICONS_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/icons/*.png")
ecm_add_app_icon(kcalc_KDEINIT_SRCS ICONS ${ICONS_SRCS})
kf5_add_kdeinit_executable( kcalc ${kcalc_KDEINIT_SRCS})
target_link_libraries(kdeinit_kcalc
Qt5::Core
Qt5::Widgets
KF5::ConfigWidgets
KF5::GuiAddons
KF5::I18n
KF5::Notifications
KF5::XmlGui
KF5::Crash
${GMP_LIBRARIES}
${MPFR_LIBRARIES}
)
install(TARGETS kdeinit_kcalc ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
target_link_libraries( kcalc kdeinit_kcalc )
install(TARGETS kcalc ${KDE_INSTALL_TARGETS_DEFAULT_ARGS} )
########### install files ###############
install( PROGRAMS org.kde.kcalc.desktop DESTINATION ${KDE_INSTALL_APPDIR})
install( FILES org.kde.kcalc.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR})
install( FILES kcalc.kcfg DESTINATION ${KDE_INSTALL_KCFGDIR})
install( FILES kcalcui.rc DESTINATION ${KDE_INSTALL_KXMLGUI5DIR}/kcalc)
install( FILES scienceconstants.xml DESTINATION ${KDE_INSTALL_DATADIR}/kcalc)
install( FILES kcalcrc.upd DESTINATION ${KDE_INSTALL_DATADIR}/kconf_update)
add_subdirectory(doc)
feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES)
diff --git a/knumber/knumber.cpp b/knumber/knumber.cpp
index 617b039..1b10e02 100644
--- a/knumber/knumber.cpp
+++ b/knumber/knumber.cpp
@@ -1,946 +1,946 @@
/*
Copyright (C) 2001 - 2013 Evan Teran
evan.teran@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#include
#include "knumber.h"
#include "knumber_base.h"
#include "knumber_error.h"
#include "knumber_float.h"
#include "knumber_fraction.h"
#include "knumber_integer.h"
#include
#include
#include
#include
QString KNumber::GroupSeparator = QStringLiteral(",");
QString KNumber::DecimalSeparator = QStringLiteral(".");
const KNumber KNumber::Zero(QStringLiteral("0"));
const KNumber KNumber::One(QStringLiteral("1"));
const KNumber KNumber::NegOne(QStringLiteral("-1"));
const KNumber KNumber::PosInfinity(QStringLiteral("inf"));
const KNumber KNumber::NegInfinity(QStringLiteral("-inf"));
const KNumber KNumber::NaN(QStringLiteral("nan"));
namespace {
namespace impl {
//------------------------------------------------------------------------------
// Name: increment
//------------------------------------------------------------------------------
void increment(QString &str, int position) {
for (int i = position; i >= 0; i--) {
const char last_char = str[i].toLatin1();
switch (last_char) {
case '0':
str[i] = QLatin1Char('1');
break;
case '1':
str[i] = QLatin1Char('2');
break;
case '2':
str[i] = QLatin1Char('3');
break;
case '3':
str[i] = QLatin1Char('4');
break;
case '4':
str[i] = QLatin1Char('5');
break;
case '5':
str[i] = QLatin1Char('6');
break;
case '6':
str[i] = QLatin1Char('7');
break;
case '7':
str[i] = QLatin1Char('8');
break;
case '8':
str[i] = QLatin1Char('9');
break;
case '9':
str[i] = QLatin1Char('0');
if (i == 0) {
str.prepend(QLatin1Char('1'));
}
continue;
case '.':
continue;
}
break;
}
}
//------------------------------------------------------------------------------
// Name: round
//------------------------------------------------------------------------------
void round(QString &str, int precision) {
// Cut off if more digits in fractional part than 'precision'
int decimalSymbolPos = str.indexOf(QLatin1Char('.'));
if (decimalSymbolPos == -1) {
if (precision == 0) {
return;
} else if (precision > 0) { // add dot if missing (and needed)
str.append(QLatin1Char('.'));
decimalSymbolPos = str.length() - 1;
}
}
// fill up with more than enough zeroes (in case fractional part too short)
str.append(QString().fill(QLatin1Char('0'), precision));
// Now decide whether to round up or down
const char last_char = str[decimalSymbolPos + precision + 1].toLatin1();
switch (last_char) {
case '0':
case '1':
case '2':
case '3':
case '4':
// nothing to do, rounding down
break;
case '5':
case '6':
case '7':
case '8':
case '9':
// rounding up
increment(str, decimalSymbolPos + precision);
break;
default:
break;
}
decimalSymbolPos = str.indexOf(QLatin1Char('.'));
str.truncate(decimalSymbolPos + precision + 1);
// if precision == 0 delete also '.'
if (precision == 0) {
str = str.section(QLatin1Char('.'), 0, 0);
}
}
}
//------------------------------------------------------------------------------
// Name: round
//------------------------------------------------------------------------------
QString round(const QString &s, int precision) {
QString tmp = s;
if (precision < 0 || !QRegExp(QLatin1String("^[+-]?\\d+(\\.\\d+)*(e[+-]?\\d+)?$")).exactMatch(tmp)) {
return s;
}
// Skip the sign (for now)
const bool neg = (tmp[0] == QLatin1Char('-'));
if (neg || tmp[0] == QLatin1Char('+')) {
tmp.remove(0, 1);
}
// Split off exponential part (including 'e'-symbol)
QString mantString = tmp.section(QLatin1Char('e'), 0, 0, QString::SectionCaseInsensitiveSeps);
QString expString = tmp.section(QLatin1Char('e'), 1, 1, QString::SectionCaseInsensitiveSeps | QString::SectionIncludeLeadingSep);
if (expString.length() == 1) {
expString.clear();
}
impl::round(mantString, precision);
if (neg) {
mantString.prepend(QLatin1Char('-'));
}
return mantString + expString;
}
}
//------------------------------------------------------------------------------
// Name: setGroupSeparator
//------------------------------------------------------------------------------
void KNumber::setGroupSeparator(const QString &ch) {
GroupSeparator = ch;
}
//------------------------------------------------------------------------------
// Name: setDecimalSeparator
//------------------------------------------------------------------------------
void KNumber::setDecimalSeparator(const QString &ch) {
DecimalSeparator = ch;
}
//------------------------------------------------------------------------------
// Name: groupSeparator
//------------------------------------------------------------------------------
QString KNumber::groupSeparator() {
return GroupSeparator;
}
//------------------------------------------------------------------------------
// Name: decimalSeparator
//------------------------------------------------------------------------------
QString KNumber::decimalSeparator() {
return DecimalSeparator;
}
//------------------------------------------------------------------------------
// Name: setDefaultFloatPrecision
//------------------------------------------------------------------------------
void KNumber::setDefaultFloatPrecision(int precision) {
// Need to transform decimal digits into binary digits
- const unsigned long int bin_prec = static_cast(double(precision) * M_LN10 / M_LN2 + 1);
- mpf_set_default_prec(bin_prec);
+ const unsigned long int bin_prec = static_cast(::ceil(precision * M_LN10 / M_LN2) + 1);
+ mpfr_set_default_prec(static_cast(bin_prec));
}
//------------------------------------------------------------------------------
// Name: setSplitoffIntegerForFractionOutput
//------------------------------------------------------------------------------
void KNumber::setSplitoffIntegerForFractionOutput(bool x) {
detail::knumber_fraction::set_split_off_integer_for_fraction_output(x);
}
//------------------------------------------------------------------------------
// Name: setDefaultFractionalInput
//------------------------------------------------------------------------------
void KNumber::setDefaultFractionalInput(bool x) {
detail::knumber_fraction::set_default_fractional_input(x);
}
//------------------------------------------------------------------------------
// Name: setDefaultFloatOutput
//------------------------------------------------------------------------------
void KNumber::setDefaultFloatOutput(bool x) {
detail::knumber_fraction::set_default_fractional_output(!x);
}
//------------------------------------------------------------------------------
// Name: Pi
//------------------------------------------------------------------------------
KNumber KNumber::Pi() {
// TODO: after 4.10 release:
// create a new constructor which works just like the normal QString
// accepting constructor, but allows us to specify separator
// characters, this will allow things to be done slightly more
// efficiently
QString s(QStringLiteral("3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068"));
s.replace(QLatin1Char('.'), DecimalSeparator);
return KNumber(s);
}
//------------------------------------------------------------------------------
// Name: Euler
//------------------------------------------------------------------------------
KNumber KNumber::Euler() {
// TODO: after 4.10 release:
// create a new constructor which works just like the normal QString
// accepting constructor, but allows us to specify separator
// characters, this will allow things to be done slightly more
// efficiently
QString s(QStringLiteral("2.7182818284590452353602874713526624977572470936999595749669676277240766303535475945713821785251664274"));
s.replace(QLatin1Char('.'), DecimalSeparator);
return KNumber(s);
}
//------------------------------------------------------------------------------
// Name: KNumber
//------------------------------------------------------------------------------
KNumber::KNumber() : value_(new detail::knumber_integer(0)) {
}
//------------------------------------------------------------------------------
// Name: KNumber
//------------------------------------------------------------------------------
KNumber::KNumber(const QString &s) : value_(nullptr) {
const QRegExp special_regex(QLatin1String("^(inf|-inf|nan)$"));
const QRegExp integer_regex(QLatin1String("^[+-]?\\d+$"));
const QRegExp fraction_regex(QLatin1String("^[+-]?\\d+/\\d+$"));
const QRegExp float_regex(QString(QLatin1String("^([+-]?\\d*)(%1\\d*)?(e([+-]?\\d+))?$")).arg(QRegExp::escape(DecimalSeparator)));
if (special_regex.exactMatch(s)) {
value_ = new detail::knumber_error(s);
} else if (integer_regex.exactMatch(s)) {
value_ = new detail::knumber_integer(s);
} else if (fraction_regex.exactMatch(s)) {
value_ = new detail::knumber_fraction(s);
simplify();
} else if (float_regex.exactMatch(s)) {
if(detail::knumber_fraction::default_fractional_input) {
const QStringList list = float_regex.capturedTexts();
if(list.size() == 5) {
const QString ipart = list[1];
const QString fpart = list[2];
const QString epart = list[3];
const int e_val = list[4].toInt();
QString num = ipart + fpart.mid(1);
QString den = QLatin1String("1") + QString(fpart.size() - 1, QLatin1Char('0'));
if(e_val < 0) {
den = den + QString(::abs(e_val), QLatin1Char('0'));
} else if(e_val > 0) {
num = num + QString(::abs(e_val), QLatin1Char('0'));
}
value_ = new detail::knumber_fraction(QStringLiteral("%1/%2").arg(num, den));
simplify();
return;
}
}
// we need to normalize the decimal separator to US style because that's
// the only type that the GMP function accept
QString new_s = s;
new_s.replace(DecimalSeparator, QLatin1String("."));
value_ = new detail::knumber_float(new_s);
simplify();
} else {
value_ = new detail::knumber_error(detail::knumber_error::ERROR_UNDEFINED);
}
}
//------------------------------------------------------------------------------
// Name: KNumber
//------------------------------------------------------------------------------
KNumber::KNumber(qint32 value) : value_(new detail::knumber_integer(value)) {
}
//------------------------------------------------------------------------------
// Name: KNumber
//------------------------------------------------------------------------------
KNumber::KNumber(qint64 value) : value_(new detail::knumber_integer(value)) {
}
//------------------------------------------------------------------------------
// Name: KNumber
//------------------------------------------------------------------------------
KNumber::KNumber(quint32 value) : value_(new detail::knumber_integer(value)) {
}
//------------------------------------------------------------------------------
// Name: KNumber
//------------------------------------------------------------------------------
KNumber::KNumber(quint64 value) : value_(new detail::knumber_integer(value)) {
}
//------------------------------------------------------------------------------
// Name: KNumber
//------------------------------------------------------------------------------
KNumber::KNumber(qint64 num, quint64 den) : value_(new detail::knumber_fraction(num, den)) {
}
//------------------------------------------------------------------------------
// Name: KNumber
//------------------------------------------------------------------------------
KNumber::KNumber(quint64 num, quint64 den) : value_(new detail::knumber_fraction(num, den)) {
}
#ifdef HAVE_LONG_DOUBLE
//------------------------------------------------------------------------------
// Name: KNumber
//------------------------------------------------------------------------------
KNumber::KNumber(long double value) : value_(new detail::knumber_float(value)) {
simplify();
}
#endif
//------------------------------------------------------------------------------
// Name: KNumber
//------------------------------------------------------------------------------
KNumber::KNumber(double value) : value_(new detail::knumber_float(value)) {
simplify();
}
//------------------------------------------------------------------------------
// Name: KNumber
//------------------------------------------------------------------------------
KNumber::KNumber(const KNumber &other) : value_(nullptr) {
if(&other != this) {
value_ = other.value_->clone();
}
}
//------------------------------------------------------------------------------
// Name: ~KNumber
//------------------------------------------------------------------------------
KNumber::~KNumber() {
delete value_;
}
//------------------------------------------------------------------------------
// Name: type
//------------------------------------------------------------------------------
KNumber::Type KNumber::type() const {
if(dynamic_cast(value_)) {
return TYPE_INTEGER;
} else if(dynamic_cast(value_)) {
return TYPE_FLOAT;
} else if(dynamic_cast(value_)) {
return TYPE_FRACTION;
} else if(dynamic_cast(value_)) {
return TYPE_ERROR;
} else {
Q_ASSERT(0);
return TYPE_ERROR;
}
}
//------------------------------------------------------------------------------
// Name: operator=
//------------------------------------------------------------------------------
KNumber &KNumber::operator=(const KNumber &rhs) {
KNumber(rhs).swap(*this);
return *this;
}
//------------------------------------------------------------------------------
// Name: swap
//------------------------------------------------------------------------------
void KNumber::swap(KNumber &other) {
qSwap(value_, other.value_);
}
//------------------------------------------------------------------------------
// Name: integerPart
//------------------------------------------------------------------------------
KNumber KNumber::integerPart() const {
KNumber x(*this);
if(detail::knumber_integer *const p = dynamic_cast(value_)) {
// NO-OP
Q_UNUSED(p);
} else if(detail::knumber_float *const p = dynamic_cast(value_)) {
detail::knumber_base *v = new detail::knumber_integer(p);
qSwap(v, x.value_);
delete v;
} else if(detail::knumber_fraction *const p = dynamic_cast(value_)) {
detail::knumber_base *v = new detail::knumber_integer(p);
qSwap(v, x.value_);
delete v;
} else if(detail::knumber_error *const p = dynamic_cast(value_)) {
// NO-OP
Q_UNUSED(p);
} else {
Q_ASSERT(0);
}
return x;
}
//------------------------------------------------------------------------------
// Name: simplify
//------------------------------------------------------------------------------
void KNumber::simplify() {
if(value_->is_integer()) {
if(detail::knumber_integer *const p = dynamic_cast(value_)) {
// NO-OP
Q_UNUSED(p);
} else if(detail::knumber_float *const p = dynamic_cast(value_)) {
detail::knumber_base *v = new detail::knumber_integer(p);
qSwap(v, value_);
delete v;
} else if(detail::knumber_fraction *const p = dynamic_cast(value_)) {
detail::knumber_base *v = new detail::knumber_integer(p);
qSwap(v, value_);
delete v;
} else if(detail::knumber_error *const p = dynamic_cast(value_)) {
// NO-OP
Q_UNUSED(p);
} else {
Q_ASSERT(0);
}
}
}
//------------------------------------------------------------------------------
// Name: operator+=
//------------------------------------------------------------------------------
KNumber &KNumber::operator+=(const KNumber &rhs) {
value_ = value_->add(rhs.value_);
simplify();
return *this;
}
//------------------------------------------------------------------------------
// Name: operator-=
//------------------------------------------------------------------------------
KNumber &KNumber::operator-=(const KNumber &rhs) {
value_ = value_->sub(rhs.value_);
simplify();
return *this;
}
//------------------------------------------------------------------------------
// Name: operator*=
//------------------------------------------------------------------------------
KNumber &KNumber::operator*=(const KNumber &rhs) {
value_ = value_->mul(rhs.value_);
simplify();
return *this;
}
//------------------------------------------------------------------------------
// Name: operator/=
//------------------------------------------------------------------------------
KNumber &KNumber::operator/=(const KNumber &rhs) {
// Fix for bug #330577, x /0 is undefined, not infinity
// Also indirectly fixes bug #329897, tan(90) is undefined, not infinity
if(rhs == Zero) {
*this = NaN;
return *this;
}
value_ = value_->div(rhs.value_);
simplify();
return *this;
}
//------------------------------------------------------------------------------
// Name: operator%=
//------------------------------------------------------------------------------
KNumber &KNumber::operator%=(const KNumber &rhs) {
value_ = value_->mod(rhs.value_);
simplify();
return *this;
}
//------------------------------------------------------------------------------
// Name: operator&=
//------------------------------------------------------------------------------
KNumber &KNumber::operator&=(const KNumber &rhs) {
value_ = value_->bitwise_and(rhs.value_);
return *this;
}
//------------------------------------------------------------------------------
// Name: operator|=
//------------------------------------------------------------------------------
KNumber &KNumber::operator|=(const KNumber &rhs) {
value_ = value_->bitwise_or(rhs.value_);
return *this;
}
//------------------------------------------------------------------------------
// Name: operator^=
//------------------------------------------------------------------------------
KNumber &KNumber::operator^=(const KNumber &rhs) {
value_ = value_->bitwise_xor(rhs.value_);
return *this;
}
//------------------------------------------------------------------------------
// Name: operator<<
//------------------------------------------------------------------------------
KNumber &KNumber::operator<<=(const KNumber &rhs) {
value_ = value_->bitwise_shift(rhs.value_);
return *this;
}
//------------------------------------------------------------------------------
// Name: operator>>=
//------------------------------------------------------------------------------
KNumber &KNumber::operator>>=(const KNumber &rhs) {
const KNumber rhs_neg(-rhs);
value_ = value_->bitwise_shift(rhs_neg.value_);
return *this;
}
//------------------------------------------------------------------------------
// Name: operator-
//------------------------------------------------------------------------------
KNumber KNumber::operator-() const {
KNumber x(*this);
x.value_ = x.value_->neg();
return x;
}
//------------------------------------------------------------------------------
// Name: operator~
//------------------------------------------------------------------------------
KNumber KNumber::operator~() const {
KNumber x(*this);
x.value_ = x.value_->cmp();
return x;
}
//------------------------------------------------------------------------------
// Name: toQString
//------------------------------------------------------------------------------
QString KNumber::toQString(int width, int precision) const {
if(value_->is_zero()) {
return QStringLiteral("0");
}
QString s;
if(detail::knumber_integer *const p = dynamic_cast(value_)) {
if(width > 0) {
s = detail::knumber_float(p).toString(width);
} else {
s = value_->toString(width);
}
} else if(detail::knumber_float *const p = dynamic_cast(value_)) {
if(width > 0) {
s = value_->toString(width);
} else {
s = value_->toString(3 * mpf_get_default_prec() / 10);
}
} else if(detail::knumber_fraction *const p = dynamic_cast(value_)) {
s = value_->toString(width);
} else {
return value_->toString(width);
}
// now do some rounding to make sure things are displayed reasonably
if (precision >= 0) {
return round(s, precision);
} else {
return s;
}
}
//------------------------------------------------------------------------------
// Name: toUint64
//------------------------------------------------------------------------------
quint64 KNumber::toUint64() const {
return value_->toUint64();
}
//------------------------------------------------------------------------------
// Name: toInt64
//------------------------------------------------------------------------------
qint64 KNumber::toInt64() const {
return value_->toInt64();
}
//------------------------------------------------------------------------------
// Name: abs
//------------------------------------------------------------------------------
KNumber KNumber::abs() const {
KNumber z(*this);
z.value_ = z.value_->abs();
z.simplify();
return z;
}
//------------------------------------------------------------------------------
// Name: cbrt
//------------------------------------------------------------------------------
KNumber KNumber::cbrt() const {
KNumber z(*this);
z.value_ = z.value_->cbrt();
z.simplify();
return z;
}
//------------------------------------------------------------------------------
// Name: sqrt
//------------------------------------------------------------------------------
KNumber KNumber::sqrt() const {
KNumber z(*this);
z.value_ = z.value_->sqrt();
z.simplify();
return z;
}
//------------------------------------------------------------------------------
// Name: pow
//------------------------------------------------------------------------------
KNumber KNumber::pow(const KNumber &x) const {
// Fix for bug #330711 (pow(0, -x) was causing crashes
// Fix for bug #330597 (pow(0,0) was 1 now it is NaN
// Thanks to Raushan Kumar for identifying the issue and submitting
// patches
if(*this == Zero && x <= Zero) {
return NaN;
}
// if the LHS is a special then we can use this function
// no matter what, cause the result is a special too
if(!dynamic_cast(value_)) {
// number much bigger than this tend to crash GMP with
// an abort
if(x > KNumber(QStringLiteral("1000000000"))) {
return PosInfinity;
}
}
KNumber z(*this);
z.value_ = z.value_->pow(x.value_);
z.simplify();
return z;
}
//------------------------------------------------------------------------------
// Name: sin
//------------------------------------------------------------------------------
KNumber KNumber::sin() const {
KNumber z(*this);
z.value_ = z.value_->sin();
z.simplify();
return z;
}
//------------------------------------------------------------------------------
// Name: cos
//------------------------------------------------------------------------------
KNumber KNumber::cos() const {
KNumber z(*this);
z.value_ = z.value_->cos();
z.simplify();
return z;
}
//------------------------------------------------------------------------------
// Name: tan
//------------------------------------------------------------------------------
KNumber KNumber::tan() const {
KNumber z(*this);
z.value_ = z.value_->tan();
z.simplify();
return z;
}
//------------------------------------------------------------------------------
// Name: tgamma
//------------------------------------------------------------------------------
KNumber KNumber::tgamma() const {
KNumber z(*this);
if(z > KNumber(QStringLiteral("10000000000"))) {
return PosInfinity;
}
z.value_ = z.value_->tgamma();
z.simplify();
return z;
}
//------------------------------------------------------------------------------
// Name: asin
//------------------------------------------------------------------------------
KNumber KNumber::asin() const {
KNumber z(*this);
z.value_ = z.value_->asin();
z.simplify();
return z;
}
//------------------------------------------------------------------------------
// Name: acos
//------------------------------------------------------------------------------
KNumber KNumber::acos() const {
KNumber z(*this);
z.value_ = z.value_->acos();
z.simplify();
return z;
}
//------------------------------------------------------------------------------
// Name: atan
//------------------------------------------------------------------------------
KNumber KNumber::atan() const {
KNumber z(*this);
z.value_ = z.value_->atan();
z.simplify();
return z;
}
//------------------------------------------------------------------------------
// Name: sinh
//------------------------------------------------------------------------------
KNumber KNumber::sinh() const {
KNumber z(*this);
z.value_ = z.value_->sinh();
z.simplify();
return z;
}
//------------------------------------------------------------------------------
// Name: cosh
//------------------------------------------------------------------------------
KNumber KNumber::cosh() const {
KNumber z(*this);
z.value_ = z.value_->cosh();
z.simplify();
return z;
}
//------------------------------------------------------------------------------
// Name: tanh
//------------------------------------------------------------------------------
KNumber KNumber::tanh() const {
KNumber z(*this);
z.value_ = z.value_->tanh();
z.simplify();
return z;
}
//------------------------------------------------------------------------------
// Name: asinh
//------------------------------------------------------------------------------
KNumber KNumber::asinh() const {
KNumber z(*this);
z.value_ = z.value_->asinh();
z.simplify();
return z;
}
//------------------------------------------------------------------------------
// Name: acosh
//------------------------------------------------------------------------------
KNumber KNumber::acosh() const {
KNumber z(*this);
z.value_ = z.value_->acosh();
z.simplify();
return z;
}
//------------------------------------------------------------------------------
// Name: atanh
//------------------------------------------------------------------------------
KNumber KNumber::atanh() const {
KNumber z(*this);
z.value_ = z.value_->atanh();
z.simplify();
return z;
}
//------------------------------------------------------------------------------
// Name: factorial
//------------------------------------------------------------------------------
KNumber KNumber::factorial() const {
KNumber z(*this);
// number much bigger than this tend to crash GMP with
// an abort
if(z > KNumber(QStringLiteral("10000000000"))) {
return PosInfinity;
}
z.value_ = z.value_->factorial();
z.simplify();
return z;
}
//------------------------------------------------------------------------------
// Name: log2
//------------------------------------------------------------------------------
KNumber KNumber::log2() const {
KNumber z(*this);
z.value_ = z.value_->log2();
z.simplify();
return z;
}
//------------------------------------------------------------------------------
// Name: log10
//------------------------------------------------------------------------------
KNumber KNumber::log10() const {
KNumber z(*this);
z.value_ = z.value_->log10();
z.simplify();
return z;
}
//------------------------------------------------------------------------------
// Name: ln
//------------------------------------------------------------------------------
KNumber KNumber::ln() const {
KNumber z(*this);
z.value_ = z.value_->ln();
z.simplify();
return z;
}
//------------------------------------------------------------------------------
// Name: floor
//------------------------------------------------------------------------------
KNumber KNumber::floor() const {
KNumber z(*this);
z.value_ = z.value_->floor();
z.simplify();
return z;
}
//------------------------------------------------------------------------------
// Name: ceil
//------------------------------------------------------------------------------
KNumber KNumber::ceil() const {
KNumber z(*this);
z.value_ = z.value_->ceil();
z.simplify();
return z;
}
//------------------------------------------------------------------------------
// Name: exp2
//------------------------------------------------------------------------------
KNumber KNumber::exp2() const {
KNumber z(*this);
z.value_ = z.value_->exp2();
z.simplify();
return z;
}
//------------------------------------------------------------------------------
// Name: exp10
//------------------------------------------------------------------------------
KNumber KNumber::exp10() const {
KNumber z(*this);
z.value_ = z.value_->exp10();
z.simplify();
return z;
}
//------------------------------------------------------------------------------
// Name: exp
//------------------------------------------------------------------------------
KNumber KNumber::exp() const {
KNumber z(*this);
z.value_ = z.value_->exp();
z.simplify();
return z;
}
//------------------------------------------------------------------------------
// Name: bin
//------------------------------------------------------------------------------
KNumber KNumber::bin(const KNumber &x) const {
KNumber z(*this);
z.value_ = z.value_->bin(x.value_);
z.simplify();
return z;
}
diff --git a/knumber/knumber_base.h b/knumber/knumber_base.h
index 150d86f..4da32c5 100644
--- a/knumber/knumber_base.h
+++ b/knumber/knumber_base.h
@@ -1,118 +1,115 @@
/*
Copyright (C) 2001 - 2013 Evan Teran
evan.teran@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#ifndef KNUMBER_BASE_H_
#define KNUMBER_BASE_H_
// Workaround: include before gmp.h to fix build with gcc-4.9
#include
#include
-
-#ifdef KNUMBER_USE_MPFR
#include
-#endif
#include
#include
namespace detail {
class knumber_error;
class knumber_integer;
class knumber_fraction;
class knumber_float;
class knumber_base {
public:
virtual ~knumber_base() = default;
public:
virtual knumber_base *clone() = 0;
public:
virtual QString toString(int precision) const = 0;
virtual quint64 toUint64() const = 0;
virtual qint64 toInt64() const = 0;
public:
virtual bool is_integer() const = 0;
virtual bool is_zero() const = 0;
virtual int sign() const = 0;
public:
// basic math
virtual knumber_base *add(knumber_base *rhs) = 0;
virtual knumber_base *sub(knumber_base *rhs) = 0;
virtual knumber_base *mul(knumber_base *rhs) = 0;
virtual knumber_base *div(knumber_base *rhs) = 0;
virtual knumber_base *mod(knumber_base *rhs) = 0;
public:
// logical operators
virtual knumber_base *bitwise_and(knumber_base *rhs) = 0;
virtual knumber_base *bitwise_xor(knumber_base *rhs) = 0;
virtual knumber_base *bitwise_or(knumber_base *rhs) = 0;
virtual knumber_base *bitwise_shift(knumber_base *rhs) = 0;
public:
// algebraic functions
virtual knumber_base *pow(knumber_base *rhs) = 0;
virtual knumber_base *neg() = 0;
virtual knumber_base *cmp() = 0;
virtual knumber_base *abs() = 0;
virtual knumber_base *sqrt() = 0;
virtual knumber_base *cbrt() = 0;
virtual knumber_base *factorial() = 0;
virtual knumber_base *reciprocal() = 0;
public:
// special functions
virtual knumber_base *log2() = 0;
virtual knumber_base *log10() = 0;
virtual knumber_base *ln() = 0;
virtual knumber_base *exp2() = 0;
virtual knumber_base *exp10() = 0;
virtual knumber_base *floor() = 0;
virtual knumber_base *ceil() = 0;
virtual knumber_base *exp() = 0;
virtual knumber_base *bin(knumber_base *rhs) = 0;
public:
// trig functions
virtual knumber_base *sin() = 0;
virtual knumber_base *cos() = 0;
virtual knumber_base *tan() = 0;
virtual knumber_base *asin() = 0;
virtual knumber_base *acos() = 0;
virtual knumber_base *atan() = 0;
virtual knumber_base *sinh() = 0;
virtual knumber_base *cosh() = 0;
virtual knumber_base *tanh() = 0;
virtual knumber_base *asinh() = 0;
virtual knumber_base *acosh() = 0;
virtual knumber_base *atanh() = 0;
virtual knumber_base *tgamma() = 0;
public:
// comparison
virtual int compare(knumber_base *rhs) = 0;
};
}
#endif
diff --git a/knumber/knumber_float.cpp b/knumber/knumber_float.cpp
index 072812e..eb6317a 100644
--- a/knumber/knumber_float.cpp
+++ b/knumber/knumber_float.cpp
@@ -1,1028 +1,693 @@
/*
Copyright (C) 2001 - 2013 Evan Teran
evan.teran@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
-#include
#include "knumber_integer.h"
#include "knumber_float.h"
#include "knumber_fraction.h"
#include "knumber_error.h"
#include
#include
#include
#ifdef _MSC_VER
double log2(double x) { return log(x) / log(2); }
double exp2(double x) { return exp(x * log(2)); }
double exp10(double x) { return exp(x * log(10)); }
#endif
// NOTE: these assume IEEE floats..
#ifndef isinf
#define isinf(x) ((x) != 0.0 && (x) + (x) == (x))
#endif
#ifndef isnan
#define isnan(x) ((x) != (x))
#endif
namespace detail {
-#ifdef KNUMBER_USE_MPFR
const mpfr_rnd_t knumber_float::rounding_mode = MPFR_RNDN;
const mpfr_prec_t knumber_float::precision = 1024;
-#endif
-template
-knumber_base *knumber_float::execute_libc_func(double x) {
- const double r = F(x);
- if(isnan(r)) {
+knumber_base *knumber_float::ensureIsValid(mpfr_ptr mpfr) {
+ if (mpfr_nan_p(mpfr)) {
knumber_error *e = new knumber_error(knumber_error::ERROR_UNDEFINED);
delete this;
return e;
- } else if(isinf(r)) {
+ } else if (mpfr_inf_p(mpfr)) {
knumber_error *e = new knumber_error(knumber_error::ERROR_POS_INFINITY);
delete this;
return e;
} else {
- mpf_set_d(mpf_, r);
return this;
}
}
-template
-knumber_base *knumber_float::execute_libc_func(double x, double y) {
- const double r = F(x, y);
- if(isnan(r)) {
- knumber_error *e = new knumber_error(knumber_error::ERROR_UNDEFINED);
- delete this;
- return e;
- } else if(isinf(r)) {
- knumber_error *e = new knumber_error(knumber_error::ERROR_POS_INFINITY);
- delete this;
- return e;
- } else {
- mpf_set_d(mpf_, r);
- return this;
- }
+template
+knumber_base *knumber_float::execute_mpfr_func() {
+ F(mpfr_, mpfr_);
+ return ensureIsValid(mpfr_);
+}
+
+template
+knumber_base *knumber_float::execute_mpfr_func() {
+ F(mpfr_, mpfr_, rounding_mode);
+ return ensureIsValid(mpfr_);
+}
+
+template
+knumber_base *knumber_float::execute_mpfr_func(mpfr_srcptr op) {
+ F(mpfr_, mpfr_, op, rounding_mode);
+ return ensureIsValid(mpfr_);
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_float::knumber_float(const QString &s) {
-
- mpf_init(mpf_);
- mpf_set_str(mpf_, s.toLatin1().constData(), 10);
+ mpfr_set_str(new_mpfr(), s.toLatin1().constData(), 10, rounding_mode);
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_float::knumber_float(double value) {
Q_ASSERT(!isinf(value));
Q_ASSERT(!isnan(value));
- mpf_init_set_d(mpf_, value);
+ mpfr_set_d(new_mpfr(), value, rounding_mode);
}
#ifdef HAVE_LONG_DOUBLE
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_float::knumber_float(long double value) {
Q_ASSERT(!isinf(value));
Q_ASSERT(!isnan(value));
- mpf_init_set_d(mpf_, value);
+ mpfr_set_ld(new_mpfr(), value, rounding_mode);
}
#endif
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
-knumber_float::knumber_float(mpf_t mpf) {
+knumber_float::knumber_float(mpfr_t mpfr) {
- mpf_init(mpf_);
- mpf_set(mpf_, mpf);
+ mpfr_set(new_mpfr(), mpfr, rounding_mode);
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_float::knumber_float(const knumber_float *value) {
-
- mpf_init_set(mpf_, value->mpf_);
+ mpfr_set(new_mpfr(), value->mpfr_, rounding_mode);
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_float::knumber_float(const knumber_integer *value) {
-
- mpf_init(mpf_);
- mpf_set_z(mpf_, value->mpz_);
+ mpfr_set_z(new_mpfr(), value->mpz_, rounding_mode);
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_float::knumber_float(const knumber_fraction *value) {
-
- mpf_init(mpf_);
- mpf_set_q(mpf_, value->mpq_);
+ mpfr_set_q(new_mpfr(), value->mpq_, rounding_mode);
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_float::clone() {
return new knumber_float(this);
}
+mpfr_ptr knumber_float::new_mpfr() {
+ mpfr_init(mpfr_);
+ return mpfr_;
+}
+
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_float::~knumber_float() {
-
- mpf_clear(mpf_);
+ mpfr_clear(mpfr_);
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_float::add(knumber_base *rhs) {
if(knumber_integer *const p = dynamic_cast(rhs)) {
knumber_float f(p);
return add(&f);
} else if(knumber_float *const p = dynamic_cast(rhs)) {
- mpf_add(mpf_, mpf_, p->mpf_);
+ mpfr_add(mpfr_, mpfr_, p->mpfr_, rounding_mode);
return this;
} else if(knumber_fraction *const p = dynamic_cast(rhs)) {
knumber_float f(p);
return add(&f);
} else if(knumber_error *const p = dynamic_cast(rhs)) {
knumber_error *e = new knumber_error(p);
delete this;
return e;
}
Q_ASSERT(0);
return nullptr;
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_float::sub(knumber_base *rhs) {
if(knumber_integer *const p = dynamic_cast(rhs)) {
knumber_float f(p);
return sub(&f);
} else if(knumber_float *const p = dynamic_cast(rhs)) {
- mpf_sub(mpf_, mpf_, p->mpf_);
+ mpfr_sub(mpfr_, mpfr_, p->mpfr_, rounding_mode);
return this;
} else if(knumber_fraction *const p = dynamic_cast(rhs)) {
knumber_float f(p);
return sub(&f);
} else if(knumber_error *const p = dynamic_cast(rhs)) {
knumber_error *e = new knumber_error(p);
delete this;
return e->neg();
}
Q_ASSERT(0);
return nullptr;
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_float::mul(knumber_base *rhs) {
if(knumber_integer *const p = dynamic_cast(rhs)) {
knumber_float f(p);
return mul(&f);
} else if(knumber_float *const p = dynamic_cast(rhs)) {
- mpf_mul(mpf_, mpf_, p->mpf_);
+ mpfr_mul(mpfr_, mpfr_, p->mpfr_, rounding_mode);
return this;
} else if(knumber_fraction *const p = dynamic_cast(rhs)) {
knumber_float f(p);
return mul(&f);
} else if(knumber_error *const p = dynamic_cast(rhs)) {
if(is_zero()) {
delete this;
return new knumber_error(knumber_error::ERROR_UNDEFINED);
}
if(sign() < 0) {
delete this;
knumber_error *e = new knumber_error(p);
return e->neg();
} else {
delete this;
return new knumber_error(p);
}
}
Q_ASSERT(0);
return nullptr;
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_float::div(knumber_base *rhs) {
if(rhs->is_zero()) {
if(sign() < 0) {
delete this;
return new knumber_error(knumber_error::ERROR_NEG_INFINITY);
} else {
delete this;
return new knumber_error(knumber_error::ERROR_POS_INFINITY);
}
}
if(knumber_integer *const p = dynamic_cast(rhs)) {
knumber_float f(p);
return div(&f);
} else if(knumber_float *const p = dynamic_cast(rhs)) {
- mpf_div(mpf_, mpf_, p->mpf_);
+ mpfr_div(mpfr_, mpfr_, p->mpfr_, rounding_mode);
return this;
} else if(knumber_fraction *const p = dynamic_cast(rhs)) {
knumber_float f(p);
return div(&f);
} else if(knumber_error *const p = dynamic_cast(rhs)) {
if(p->sign() > 0 || p->sign() < 0) {
delete this;
return new knumber_integer(0);
}
delete this;
return new knumber_error(p);
}
Q_ASSERT(0);
return nullptr;
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_float::mod(knumber_base *rhs) {
Q_UNUSED(rhs);
if(rhs->is_zero()) {
delete this;
return new knumber_error(knumber_error::ERROR_UNDEFINED);
}
delete this;
return new knumber_integer(0);
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_float::bitwise_and(knumber_base *rhs) {
Q_UNUSED(rhs);
delete this;
return new knumber_integer(0);
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_float::bitwise_xor(knumber_base *rhs) {
Q_UNUSED(rhs);
delete this;
return new knumber_integer(0);
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_float::bitwise_or(knumber_base *rhs) {
Q_UNUSED(rhs);
delete this;
return new knumber_integer(0);
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_float::bitwise_shift(knumber_base *rhs) {
Q_UNUSED(rhs);
delete this;
// NOTE: we don't support bitwise operations with non-integer operands
return new knumber_error(knumber_error::ERROR_UNDEFINED);
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_float::neg() {
-
- mpf_neg(mpf_, mpf_);
+ mpfr_neg(mpfr_, mpfr_, rounding_mode);
return this;
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_float::cmp() {
delete this;
return new knumber_error(knumber_error::ERROR_UNDEFINED);
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_float::abs() {
-
- mpf_abs(mpf_, mpf_);
+ mpfr_abs(mpfr_, mpfr_, rounding_mode);
return this;
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_float::sqrt() {
if(sign() < 0) {
delete this;
return new knumber_error(knumber_error::ERROR_UNDEFINED);
}
-#ifdef KNUMBER_USE_MPFR
- mpfr_t mpfr;
- mpfr_init_set_f(mpfr, mpf_, rounding_mode);
- mpfr_sqrt(mpfr, mpfr, rounding_mode);
- mpfr_get_f(mpf_, mpfr, rounding_mode);
- mpfr_clear(mpfr);
-#else
- mpf_sqrt(mpf_, mpf_);
-#endif
+ mpfr_sqrt(mpfr_, mpfr_, rounding_mode);
return this;
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_float::cbrt() {
-
-#ifdef KNUMBER_USE_MPFR
- mpfr_t mpfr;
- mpfr_init_set_f(mpfr, mpf_, rounding_mode);
- mpfr_cbrt(mpfr, mpfr, rounding_mode);
- mpfr_get_f(mpf_, mpfr, rounding_mode);
- mpfr_clear(mpfr);
-#else
- const double x = mpf_get_d(mpf_);
- if(isinf(x)) {
- delete this;
- return new knumber_error(knumber_error::ERROR_POS_INFINITY);
- } else {
-#ifdef Q_CC_MSVC
- return execute_libc_func< ::pow>(x, 1.0 / 3.0);
-#else
- return execute_libc_func< ::cbrt>(x);
-#endif
- }
-#endif
- return this;
+ return execute_mpfr_func< ::mpfr_cbrt>();
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_float::factorial() {
if(sign() < 0) {
delete this;
return new knumber_error(knumber_error::ERROR_UNDEFINED);
}
knumber_integer *i = new knumber_integer(this);
delete this;
return i->factorial();
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_float::sin() {
-
-#ifdef KNUMBER_USE_MPFR
- mpfr_t mpfr;
- mpfr_init_set_f(mpfr, mpf_, rounding_mode);
- mpfr_sin(mpfr, mpfr, rounding_mode);
- mpfr_get_f(mpf_, mpfr, rounding_mode);
- mpfr_clear(mpfr);
- return this;
-#else
- const double x = mpf_get_d(mpf_);
- if(isinf(x)) {
- delete this;
- return new knumber_error(knumber_error::ERROR_POS_INFINITY);
- } else {
- return execute_libc_func< ::sin>(x);
- }
-#endif
-
+ return execute_mpfr_func< ::mpfr_sin>();
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_float::floor() {
-#ifdef KNUMBER_USE_MPFR
- mpfr_t mpfr;
- mpfr_init_set_f(mpfr, mpf_, rounding_mode);
- mpfr_floor(mpfr, mpfr);
- mpfr_get_f(mpf_, mpfr, rounding_mode);
- mpfr_clear(mpfr);
- return this;
-#else
- const double x = mpf_get_d(mpf_);
- if(isinf(x)) {
- delete this;
- return new knumber_error(knumber_error::ERROR_POS_INFINITY);
- } else {
- return execute_libc_func< ::floor>(x);
- }
-#endif
+ return execute_mpfr_func< ::mpfr_floor>();
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_float::ceil() {
-#ifdef KNUMBER_USE_MPFR
- mpfr_t mpfr;
- mpfr_init_set_f(mpfr, mpf_, rounding_mode);
- mpfr_ceil(mpfr, mpfr);
- mpfr_get_f(mpf_, mpfr, rounding_mode);
- mpfr_clear(mpfr);
- return this;
-#else
- const double x = mpf_get_d(mpf_);
- if(isinf(x)) {
- delete this;
- return new knumber_error(knumber_error::ERROR_POS_INFINITY);
- } else {
- return execute_libc_func< ::ceil>(x);
- }
-#endif
+ return execute_mpfr_func< ::mpfr_ceil>();
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_float::cos() {
-
-#ifdef KNUMBER_USE_MPFR
- mpfr_t mpfr;
- mpfr_init_set_f(mpfr, mpf_, rounding_mode);
- mpfr_cos(mpfr, mpfr, rounding_mode);
- mpfr_get_f(mpf_, mpfr, rounding_mode);
- mpfr_clear(mpfr);
- return this;
-#else
- const double x = mpf_get_d(mpf_);
- if(isinf(x)) {
- delete this;
- return new knumber_error(knumber_error::ERROR_POS_INFINITY);
- } else {
- return execute_libc_func< ::cos>(x);
- }
-#endif
+ return execute_mpfr_func< ::mpfr_cos>();
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_float::tan() {
-
-#ifdef KNUMBER_USE_MPFR
- mpfr_t mpfr;
- mpfr_init_set_f(mpfr, mpf_, rounding_mode);
- mpfr_tan(mpfr, mpfr, rounding_mode);
- mpfr_get_f(mpf_, mpfr, rounding_mode);
- mpfr_clear(mpfr);
- return this;
-#else
- const double x = mpf_get_d(mpf_);
- if(isinf(x)) {
- delete this;
- return new knumber_error(knumber_error::ERROR_POS_INFINITY);
- } else {
- return execute_libc_func< ::tan>(x);
- }
-#endif
+ return execute_mpfr_func< ::mpfr_tan>();
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_float::asin() {
- if(mpf_cmp_d(mpf_, 1.0) > 0 || mpf_cmp_d(mpf_, -1.0) < 0) {
+ if (mpfr_cmp_d(mpfr_, 1.0) > 0 || mpfr_cmp_d(mpfr_, -1.0) < 0) {
delete this;
return new knumber_error(knumber_error::ERROR_UNDEFINED);
}
-#ifdef KNUMBER_USE_MPFR
- mpfr_t mpfr;
- mpfr_init_set_f(mpfr, mpf_, rounding_mode);
- mpfr_asin(mpfr, mpfr, rounding_mode);
- mpfr_get_f(mpf_, mpfr, rounding_mode);
- mpfr_clear(mpfr);
- return this;
-#else
- const double x = mpf_get_d(mpf_);
- if(isinf(x)) {
- delete this;
- return new knumber_error(knumber_error::ERROR_POS_INFINITY);
- } else {
- return execute_libc_func< ::asin>(x);
- }
-#endif
+ return execute_mpfr_func< ::mpfr_asin>();
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------s
knumber_base *knumber_float::acos() {
- if(mpf_cmp_d(mpf_, 1.0) > 0 || mpf_cmp_d(mpf_, -1.0) < 0) {
+ if (mpfr_cmp_d(mpfr_, 1.0) > 0 || mpfr_cmp_d(mpfr_, -1.0) < 0) {
delete this;
return new knumber_error(knumber_error::ERROR_UNDEFINED);
}
-#ifdef KNUMBER_USE_MPFR
- mpfr_t mpfr;
- mpfr_init_set_f(mpfr, mpf_, rounding_mode);
- mpfr_acos(mpfr, mpfr, rounding_mode);
- mpfr_get_f(mpf_, mpfr, rounding_mode);
- mpfr_clear(mpfr);
- return this;
-#else
- const double x = mpf_get_d(mpf_);
- if(isinf(x)) {
- delete this;
- return new knumber_error(knumber_error::ERROR_POS_INFINITY);
- } else {
- return execute_libc_func< ::acos>(x);
- }
-#endif
+ return execute_mpfr_func< ::mpfr_acos>();
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_float::atan() {
-
-#ifdef KNUMBER_USE_MPFR
- mpfr_t mpfr;
- mpfr_init_set_f(mpfr, mpf_, rounding_mode);
- mpfr_atan(mpfr, mpfr, rounding_mode);
- mpfr_get_f(mpf_, mpfr, rounding_mode);
- mpfr_clear(mpfr);
- return this;
-#else
- const double x = mpf_get_d(mpf_);
- if(isinf(x)) {
- delete this;
- return new knumber_error(knumber_error::ERROR_POS_INFINITY);
- } else {
- return execute_libc_func< ::atan>(x);
- }
-#endif
+ return execute_mpfr_func< ::mpfr_atan>();
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_float::sinh() {
-#ifdef KNUMBER_USE_MPFR
- mpfr_t mpfr;
- mpfr_init_set_f(mpfr, mpf_, rounding_mode);
- mpfr_sinh(mpfr, mpfr, rounding_mode);
- mpfr_get_f(mpf_, mpfr, rounding_mode);
- mpfr_clear(mpfr);
- return this;
-#else
- const double x = mpf_get_d(mpf_);
- return execute_libc_func< ::sinh>(x);
-#endif
-
+ return execute_mpfr_func< ::mpfr_sinh>();
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_float::cosh() {
-#ifdef KNUMBER_USE_MPFR
- mpfr_t mpfr;
- mpfr_init_set_f(mpfr, mpf_, rounding_mode);
- mpfr_cosh(mpfr, mpfr, rounding_mode);
- mpfr_get_f(mpf_, mpfr, rounding_mode);
- mpfr_clear(mpfr);
- return this;
-#else
- const double x = mpf_get_d(mpf_);
- return execute_libc_func< ::cosh>(x);
-#endif
+ return execute_mpfr_func< ::mpfr_cosh>();
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_float::tanh() {
-#ifdef KNUMBER_USE_MPFR
- mpfr_t mpfr;
- mpfr_init_set_f(mpfr, mpf_, rounding_mode);
- mpfr_tanh(mpfr, mpfr, rounding_mode);
- mpfr_get_f(mpf_, mpfr, rounding_mode);
- mpfr_clear(mpfr);
- return this;
-#else
- const double x = mpf_get_d(mpf_);
- return execute_libc_func< ::tanh>(x);
-#endif
+ return execute_mpfr_func< ::mpfr_tanh>();
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_float::tgamma() {
-
-#ifdef KNUMBER_USE_MPFR
- mpfr_t mpfr;
- mpfr_init_set_f(mpfr, mpf_, rounding_mode);
- mpfr_gamma(mpfr, mpfr, rounding_mode);
- mpfr_get_f(mpf_, mpfr, rounding_mode);
- mpfr_clear(mpfr);
- return this;
-#else
- const double x = mpf_get_d(mpf_);
- if(isinf(x)) {
- delete this;
- return new knumber_error(knumber_error::ERROR_POS_INFINITY);
-
- } else {
- return execute_libc_func< ::tgamma>(x);
- }
-#endif
-
+ return execute_mpfr_func< ::mpfr_gamma>();
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_float::asinh() {
-#ifdef KNUMBER_USE_MPFR
- mpfr_t mpfr;
- mpfr_init_set_f(mpfr, mpf_, rounding_mode);
- mpfr_asinh(mpfr, mpfr, rounding_mode);
- mpfr_get_f(mpf_, mpfr, rounding_mode);
- mpfr_clear(mpfr);
- return this;
-#else
- const double x = mpf_get_d(mpf_);
- return execute_libc_func< ::asinh>(x);
-#endif
+ return execute_mpfr_func< ::mpfr_asinh>();
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_float::acosh() {
-#ifdef KNUMBER_USE_MPFR
- mpfr_t mpfr;
- mpfr_init_set_f(mpfr, mpf_, rounding_mode);
- mpfr_acosh(mpfr, mpfr, rounding_mode);
- mpfr_get_f(mpf_, mpfr, rounding_mode);
- mpfr_clear(mpfr);
- return this;
-#else
- const double x = mpf_get_d(mpf_);
- return execute_libc_func< ::acosh>(x);
-#endif
+ return execute_mpfr_func< ::mpfr_acosh>();
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_float::atanh() {
-#ifdef KNUMBER_USE_MPFR
- mpfr_t mpfr;
- mpfr_init_set_f(mpfr, mpf_, rounding_mode);
- mpfr_atanh(mpfr, mpfr, rounding_mode);
- mpfr_get_f(mpf_, mpfr, rounding_mode);
- mpfr_clear(mpfr);
- return this;
-#else
- const double x = mpf_get_d(mpf_);
- return execute_libc_func< ::atanh>(x);
-#endif
+ return execute_mpfr_func< ::mpfr_atanh>();
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_float::pow(knumber_base *rhs) {
if(knumber_integer *const p = dynamic_cast(rhs)) {
- mpf_pow_ui(mpf_, mpf_, mpz_get_ui(p->mpz_));
+ mpfr_pow_ui(mpfr_, mpfr_, mpz_get_ui(p->mpz_), rounding_mode);
if(p->sign() < 0) {
return reciprocal();
} else {
return this;
}
} else if(knumber_float *const p = dynamic_cast(rhs)) {
- return execute_libc_func< ::pow>(mpf_get_d(mpf_), mpf_get_d(p->mpf_));
+ return execute_mpfr_func< ::mpfr_pow>(p->mpfr_);
} else if(knumber_fraction *const p = dynamic_cast(rhs)) {
knumber_float f(p);
- return execute_libc_func< ::pow>(mpf_get_d(mpf_), mpf_get_d(f.mpf_));
+ return execute_mpfr_func< ::mpfr_pow>(f.mpfr_);
} else if(knumber_error *const p = dynamic_cast(rhs)) {
if(p->sign() > 0) {
knumber_error *e = new knumber_error(knumber_error::ERROR_POS_INFINITY);
delete this;
return e;
} else if(p->sign() < 0) {
knumber_integer *n = new knumber_integer(0);
delete this;
return n;
} else {
knumber_error *e = new knumber_error(knumber_error::ERROR_UNDEFINED);
delete this;
return e;
}
}
Q_ASSERT(0);
return nullptr;
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
int knumber_float::compare(knumber_base *rhs) {
if(knumber_integer *const p = dynamic_cast(rhs)) {
knumber_float f(p);
return compare(&f);
} else if(knumber_float *const p = dynamic_cast(rhs)) {
- return mpf_cmp(mpf_, p->mpf_);
+ return mpfr_cmp(mpfr_, p->mpfr_);
} else if(knumber_fraction *const p = dynamic_cast(rhs)) {
knumber_float f(p);
return compare(&f);
} else if(knumber_error *const p = dynamic_cast(rhs)) {
// NOTE: any number compared to NaN/Inf/-Inf always compares less
// at the moment
return -1;
}
Q_ASSERT(0);
return 0;
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
QString knumber_float::toString(int precision) const {
size_t size;
+
if (precision > 0) {
- size = gmp_snprintf(nullptr, 0, "%.*Fg", precision, mpf_) + 1;
+ size = static_cast(mpfr_snprintf(nullptr, 0, "%.*Rg", precision, mpfr_) + 1);
} else {
- size = gmp_snprintf(nullptr, 0, "%.Fg", mpf_) + 1;
+ size = static_cast(mpfr_snprintf(nullptr, 0, "%.Rg", mpfr_) + 1);
}
QScopedArrayPointer buf(new char[size]);
if (precision > 0) {
- gmp_snprintf(&buf[0], size, "%.*Fg", precision, mpf_);
+ mpfr_snprintf(&buf[0], size, "%.*Rg", precision, mpfr_);
} else {
- gmp_snprintf(&buf[0], size, "%.Fg", mpf_);
+ mpfr_snprintf(&buf[0], size, "%.Rg", mpfr_);
}
return QLatin1String(&buf[0]);
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
bool knumber_float::is_integer() const {
-
- return mpf_integer_p(mpf_) != 0;
+ return mpfr_integer_p(mpfr_) != 0;
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
bool knumber_float::is_zero() const {
-
- return mpf_sgn(mpf_) == 0;
+ return mpfr_zero_p(mpfr_);
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
int knumber_float::sign() const {
-
- return mpf_sgn(mpf_);
+ return mpfr_sgn(mpfr_);
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_float::reciprocal() {
-
- mpf_t mpf;
- mpf_init_set_d(mpf, 1.0);
- mpf_div(mpf_, mpf, mpf_);
+ mpfr_t mpfr;
+ mpfr_init_set_d(mpfr, 1.0, rounding_mode);
+ mpfr_div(mpfr_, mpfr, mpfr_, rounding_mode);
+ mpfr_clear(mpfr);
return this;
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_float::log2() {
-#ifdef KNUMBER_USE_MPFR
- mpfr_t mpfr;
- mpfr_init_set_f(mpfr, mpf_, rounding_mode);
- mpfr_log2(mpfr, mpfr, rounding_mode);
- mpfr_get_f(mpf_, mpfr, rounding_mode);
- mpfr_clear(mpfr);
- return this;
-#else
- const double x = mpf_get_d(mpf_);
- if(isinf(x)) {
- delete this;
- return new knumber_error(knumber_error::ERROR_POS_INFINITY);
- } else {
- return execute_libc_func< ::log2>(x);
- }
-#endif
+ return execute_mpfr_func< ::mpfr_log2>();
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_float::log10() {
-#ifdef KNUMBER_USE_MPFR
- mpfr_t mpfr;
- mpfr_init_set_f(mpfr, mpf_, rounding_mode);
- mpfr_log10(mpfr, mpfr, rounding_mode);
- mpfr_get_f(mpf_, mpfr, rounding_mode);
- mpfr_clear(mpfr);
- return this;
-#else
- const double x = mpf_get_d(mpf_);
- if(isinf(x)) {
- delete this;
- return new knumber_error(knumber_error::ERROR_POS_INFINITY);
- } else {
- return execute_libc_func< ::log10>(x);
- }
-#endif
+ return execute_mpfr_func< ::mpfr_log10>();
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_float::ln() {
-#ifdef KNUMBER_USE_MPFR
- mpfr_t mpfr;
- mpfr_init_set_f(mpfr, mpf_, rounding_mode);
- mpfr_log(mpfr, mpfr, rounding_mode);
- mpfr_get_f(mpf_, mpfr, rounding_mode);
- mpfr_clear(mpfr);
- return this;
-#else
- const double x = mpf_get_d(mpf_);
- if(isinf(x)) {
- delete this;
- return new knumber_error(knumber_error::ERROR_POS_INFINITY);
- } else {
- return execute_libc_func< ::log>(x);
- }
-#endif
+ return execute_mpfr_func< ::mpfr_log>();
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_float::exp2() {
-#ifdef KNUMBER_USE_MPFR
- mpfr_t mpfr;
- mpfr_init_set_f(mpfr, mpf_, rounding_mode);
- mpfr_exp2(mpfr, mpfr, rounding_mode);
- mpfr_get_f(mpf_, mpfr, rounding_mode);
- mpfr_clear(mpfr);
- return this;
-#else
- const double x = mpf_get_d(mpf_);
- if(isinf(x)) {
- delete this;
- return new knumber_error(knumber_error::ERROR_POS_INFINITY);
- } else {
- return execute_libc_func< ::exp2>(x);
- }
-#endif
+ return execute_mpfr_func< ::mpfr_exp2>();
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_float::exp10() {
-#ifdef KNUMBER_USE_MPFR
- mpfr_t mpfr;
- mpfr_init_set_f(mpfr, mpf_, rounding_mode);
- mpfr_exp10(mpfr, mpfr, rounding_mode);
- mpfr_get_f(mpf_, mpfr, rounding_mode);
- mpfr_clear(mpfr);
- return this;
-#else
- const double x = mpf_get_d(mpf_);
- if(isinf(x)) {
- delete this;
- return new knumber_error(knumber_error::ERROR_POS_INFINITY);
- } else {
- return execute_libc_func< ::pow>(10, x);
- }
-#endif
+ return execute_mpfr_func< ::mpfr_exp10>();
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_float::exp() {
-#ifdef KNUMBER_USE_MPFR
- mpfr_t mpfr;
- mpfr_init_set_f(mpfr, mpf_, rounding_mode);
- mpfr_exp(mpfr, mpfr, rounding_mode);
- mpfr_get_f(mpf_, mpfr, rounding_mode);
- mpfr_clear(mpfr);
- return this;
-#else
- const double x = mpf_get_d(mpf_);
- if(isinf(x)) {
- delete this;
- return new knumber_error(knumber_error::ERROR_POS_INFINITY);
- } else {
- return execute_libc_func< ::exp>(x);
- }
-#endif
+ return execute_mpfr_func< ::mpfr_exp>();
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
quint64 knumber_float::toUint64() const {
return knumber_integer(this).toUint64();
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
qint64 knumber_float::toInt64() const {
return knumber_integer(this).toInt64();
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_float::bin(knumber_base *rhs) {
Q_UNUSED(rhs);
delete this;
return new knumber_error(knumber_error::ERROR_UNDEFINED);
}
}
diff --git a/knumber/knumber_float.h b/knumber/knumber_float.h
index f9ed9fc..afa4be1 100644
--- a/knumber/knumber_float.h
+++ b/knumber/knumber_float.h
@@ -1,135 +1,141 @@
/*
Copyright (C) 2001 - 2013 Evan Teran
evan.teran@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#ifndef KNUMBER_FLOAT_H_
#define KNUMBER_FLOAT_H_
+#include
#include "knumber_base.h"
class KNumber;
namespace detail {
class knumber_float : public knumber_base {
friend class ::KNumber;
friend class knumber_error;
friend class knumber_integer;
friend class knumber_fraction;
private:
-#ifdef KNUMBER_USE_MPFR
static const mpfr_rnd_t rounding_mode;
static const mpfr_prec_t precision;
-#endif
public:
explicit knumber_float(const QString &s);
explicit knumber_float(double value);
#ifdef HAVE_LONG_DOUBLE
explicit knumber_float(long double value);
#endif
- explicit knumber_float(mpf_t mpf);
+ explicit knumber_float(mpfr_t mpfr);
~knumber_float() override;
private:
// conversion constructors
explicit knumber_float(const knumber_integer *value);
explicit knumber_float(const knumber_fraction *value);
explicit knumber_float(const knumber_float *value);
explicit knumber_float(const knumber_error *value);
public:
QString toString(int precision) const override;
quint64 toUint64() const override;
qint64 toInt64() const override;
public:
bool is_integer() const override;
bool is_zero() const override;
int sign() const override;
public:
knumber_base *add(knumber_base *rhs) override;
knumber_base *sub(knumber_base *rhs) override;
knumber_base *mul(knumber_base *rhs) override;
knumber_base *div(knumber_base *rhs) override;
knumber_base *mod(knumber_base *rhs) override;
public:
knumber_base *pow(knumber_base *rhs) override;
knumber_base *neg() override;
knumber_base *cmp() override;
knumber_base *abs() override;
knumber_base *sqrt() override;
knumber_base *cbrt() override;
knumber_base *factorial() override;
knumber_base *reciprocal() override;
knumber_base *tgamma() override;
public:
knumber_base *log2() override;
knumber_base *log10() override;
knumber_base *ln() override;
knumber_base *floor() override;
knumber_base *ceil() override;
knumber_base *exp2() override;
knumber_base *exp10() override;
knumber_base *exp() override;
knumber_base *bin(knumber_base *rhs) override;
public:
knumber_base *sin() override;
knumber_base *cos() override;
knumber_base *tan() override;
knumber_base *asin() override;
knumber_base *acos() override;
knumber_base *atan() override;
knumber_base *sinh() override;
knumber_base *cosh() override;
knumber_base *tanh() override;
knumber_base *asinh() override;
knumber_base *acosh() override;
knumber_base *atanh() override;
public:
int compare(knumber_base *rhs) override;
public:
knumber_base *bitwise_and(knumber_base *rhs) override;
knumber_base *bitwise_xor(knumber_base *rhs) override;
knumber_base *bitwise_or(knumber_base *rhs) override;
knumber_base *bitwise_shift(knumber_base *rhs) override;
public:
knumber_base *clone() override;
private:
- template
- knumber_base *execute_libc_func(double x);
+ knumber_base *ensureIsValid(mpfr_ptr mpfr);
+
+ template
+ knumber_base *execute_mpfr_func();
+
+ template
+ knumber_base *execute_mpfr_func();
+
+ template
+ knumber_base *execute_mpfr_func(mpfr_srcptr op);
- template
- knumber_base *execute_libc_func(double x, double y);
+ mpfr_ptr new_mpfr();
private:
- mpf_t mpf_;
+ mpfr_t mpfr_;
};
}
#endif
diff --git a/knumber/knumber_integer.cpp b/knumber/knumber_integer.cpp
index ad192f4..5a49acf 100644
--- a/knumber/knumber_integer.cpp
+++ b/knumber/knumber_integer.cpp
@@ -1,888 +1,895 @@
/*
Copyright (C) 2001 - 2013 Evan Teran
evan.teran@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#include
#include "knumber_integer.h"
#include "knumber_float.h"
#include "knumber_fraction.h"
#include "knumber_error.h"
#include
#include
namespace detail {
//------------------------------------------------------------------------------
// Name: knumber_integer
//------------------------------------------------------------------------------
knumber_integer::knumber_integer(const QString &s) {
mpz_init(mpz_);
mpz_set_str(mpz_, s.toLatin1().constData(), 10);
}
//------------------------------------------------------------------------------
// Name: knumber_integer
//------------------------------------------------------------------------------
knumber_integer::knumber_integer(qint32 value) {
mpz_init_set_si(mpz_, static_cast(value));
}
//------------------------------------------------------------------------------
// Name: knumber_integer
//------------------------------------------------------------------------------
knumber_integer::knumber_integer(qint64 value) {
mpz_init(mpz_);
#if SIZEOF_SIGNED_LONG == 8
mpz_set_si(mpz_, static_cast(value));
#elif SIZEOF_SIGNED_LONG == 4
mpz_set_si(mpz_, static_cast(value >> 32));
mpz_mul_2exp(mpz_, mpz_, 32);
mpz_add_ui(mpz_, mpz_, static_cast(value));
#else
#error "SIZEOF_SIGNED_LONG is a unhandled case"
#endif
}
//------------------------------------------------------------------------------
// Name: knumber_integer
//------------------------------------------------------------------------------
knumber_integer::knumber_integer(quint32 value) {
mpz_init_set_ui(mpz_, static_cast(value));
}
//------------------------------------------------------------------------------
// Name: knumber_integer
//------------------------------------------------------------------------------
knumber_integer::knumber_integer(quint64 value) {
mpz_init(mpz_);
#if SIZEOF_UNSIGNED_LONG == 8
mpz_set_ui(mpz_, static_cast(value));
#elif SIZEOF_UNSIGNED_LONG == 4
mpz_set_ui(mpz_, static_cast(value >> 32));
mpz_mul_2exp(mpz_, mpz_, 32);
mpz_add_ui(mpz_, mpz_, static_cast(value));
#else
#error "SIZEOF_UNSIGNED_LONG is a unhandled case"
#endif
}
//------------------------------------------------------------------------------
// Name: knumber_integer
//------------------------------------------------------------------------------
knumber_integer::knumber_integer(mpz_t mpz) {
mpz_init_set(mpz_, mpz);
}
//------------------------------------------------------------------------------
// Name: knumber_integer
//------------------------------------------------------------------------------
knumber_integer::knumber_integer(const knumber_integer *value) {
mpz_init_set(mpz_, value->mpz_);
}
//------------------------------------------------------------------------------
// Name: knumber_integer
//------------------------------------------------------------------------------
knumber_integer::knumber_integer(const knumber_float *value) {
mpz_init(mpz_);
- mpz_set_f(mpz_, value->mpf_);
+
+ mpf_t mpf;
+ mpf_init(mpf);
+
+ mpfr_get_f(mpf, value->mpfr_, knumber_float::rounding_mode);
+ mpz_set_f(mpz_, mpf);
+
+ mpf_clear(mpf);
}
//------------------------------------------------------------------------------
// Name: knumber_integer
//------------------------------------------------------------------------------
knumber_integer::knumber_integer(const knumber_fraction *value) {
mpz_init(mpz_);
mpz_set_q(mpz_, value->mpq_);
}
//------------------------------------------------------------------------------
// Name: clone
//------------------------------------------------------------------------------
knumber_base *knumber_integer::clone() {
return new knumber_integer(this);
}
//------------------------------------------------------------------------------
// Name: ~knumber_integer
//------------------------------------------------------------------------------
knumber_integer::~knumber_integer() {
mpz_clear(mpz_);
}
//------------------------------------------------------------------------------
// Name: add
//------------------------------------------------------------------------------
knumber_base *knumber_integer::add(knumber_base *rhs) {
if(knumber_integer *const p = dynamic_cast(rhs)) {
mpz_add(mpz_, mpz_, p->mpz_);
return this;
} else if(knumber_float *const p = dynamic_cast(rhs)) {
knumber_float *const f = new knumber_float(this);
delete this;
return f->add(p);
} else if(knumber_fraction *const p = dynamic_cast(rhs)) {
knumber_fraction *const q = new knumber_fraction(this);
delete this;
return q->add(p);
} else if(knumber_error *const p = dynamic_cast(rhs)) {
delete this;
return p->clone();
}
Q_ASSERT(0);
return nullptr;
}
//------------------------------------------------------------------------------
// Name: sub
//------------------------------------------------------------------------------
knumber_base *knumber_integer::sub(knumber_base *rhs) {
if(knumber_integer *const p = dynamic_cast(rhs)) {
mpz_sub(mpz_, mpz_, p->mpz_);
return this;
} else if(knumber_float *const p = dynamic_cast(rhs)) {
knumber_float *f = new knumber_float(this);
delete this;
return f->sub(p);
} else if(knumber_fraction *const p = dynamic_cast(rhs)) {
knumber_fraction *q = new knumber_fraction(this);
delete this;
return q->sub(p);
} else if(knumber_error *const p = dynamic_cast(rhs)) {
knumber_base *e = p->clone();
delete this;
return e->neg();
}
Q_ASSERT(0);
return nullptr;
}
//------------------------------------------------------------------------------
// Name: mul
//------------------------------------------------------------------------------
knumber_base *knumber_integer::mul(knumber_base *rhs) {
if(knumber_integer *const p = dynamic_cast(rhs)) {
mpz_mul(mpz_, mpz_, p->mpz_);
return this;
} else if(knumber_float *const p = dynamic_cast(rhs)) {
knumber_float *f = new knumber_float(this);
delete this;
return f->mul(p);
} else if(knumber_fraction *const p = dynamic_cast(rhs)) {
knumber_fraction *q = new knumber_fraction(this);
delete this;
return q->mul(p);
} else if(knumber_error *const p = dynamic_cast(rhs)) {
if(is_zero()) {
delete this;
knumber_error *e = new knumber_error(knumber_error::ERROR_UNDEFINED);
return e->neg();
}
if(sign() < 0) {
delete this;
knumber_base *e = p->clone();
return e->neg();
} else {
delete this;
return p->clone();
}
}
Q_ASSERT(0);
return nullptr;
}
//------------------------------------------------------------------------------
// Name: div
//------------------------------------------------------------------------------
knumber_base *knumber_integer::div(knumber_base *rhs) {
if(rhs->is_zero()) {
if(sign() < 0) {
delete this;
return new knumber_error(knumber_error::ERROR_NEG_INFINITY);
} else {
delete this;
return new knumber_error(knumber_error::ERROR_POS_INFINITY);
}
}
if(knumber_integer *const p = dynamic_cast(rhs)) {
knumber_fraction *q = new knumber_fraction(this);
delete this;
return q->div(p);
} else if(knumber_float *const p = dynamic_cast(rhs)) {
knumber_float *f = new knumber_float(this);
delete this;
return f->div(p);
} else if(knumber_fraction *const p = dynamic_cast(rhs)) {
knumber_fraction *q = new knumber_fraction(this);
delete this;
return q->div(p);
} else if(knumber_error *const p = dynamic_cast(rhs)) {
if(p->sign() > 0) {
delete this;
return new knumber_integer(0);
} else if(p->sign() < 0) {
delete this;
return new knumber_integer(0);
}
delete this;
return p->clone();
}
Q_ASSERT(0);
return nullptr;
}
//------------------------------------------------------------------------------
// Name: mod
//------------------------------------------------------------------------------
knumber_base *knumber_integer::mod(knumber_base *rhs) {
if(rhs->is_zero()) {
delete this;
return new knumber_error(knumber_error::ERROR_UNDEFINED);
}
if(knumber_integer *const p = dynamic_cast(rhs)) {
mpz_mod(mpz_, mpz_, p->mpz_);
return this;
} else if(knumber_float *const p = dynamic_cast(rhs)) {
knumber_float *f = new knumber_float(this);
delete this;
return f->mod(p);
} else if(knumber_fraction *const p = dynamic_cast(rhs)) {
knumber_fraction *q = new knumber_fraction(this);
delete this;
return q->mod(p);
} else if(knumber_error *const p = dynamic_cast(rhs)) {
delete this;
return p->clone();
}
Q_ASSERT(0);
return nullptr;
}
//------------------------------------------------------------------------------
// Name: bitwise_and
//------------------------------------------------------------------------------
knumber_base *knumber_integer::bitwise_and(knumber_base *rhs) {
if(knumber_integer *const p = dynamic_cast(rhs)) {
mpz_and(mpz_, mpz_, p->mpz_);
return this;
} else if(knumber_float *const p = dynamic_cast(rhs)) {
knumber_float *f = new knumber_float(this);
delete this;
return f->bitwise_and(p);
} else if(knumber_fraction *const p = dynamic_cast(rhs)) {
knumber_fraction *f = new knumber_fraction(this);
delete this;
return f->bitwise_and(p);
} else if(knumber_error *const p = dynamic_cast(rhs)) {
delete this;
return p->clone();
}
Q_ASSERT(0);
return nullptr;
}
//------------------------------------------------------------------------------
// Name: bitwise_xor
//------------------------------------------------------------------------------
knumber_base *knumber_integer::bitwise_xor(knumber_base *rhs) {
if(knumber_integer *const p = dynamic_cast(rhs)) {
mpz_xor(mpz_, mpz_, p->mpz_);
return this;
} else if(knumber_float *const p = dynamic_cast(rhs)) {
knumber_float *f = new knumber_float(this);
delete this;
return f->bitwise_xor(p);
} else if(knumber_fraction *const p = dynamic_cast(rhs)) {
knumber_fraction *f = new knumber_fraction(this);
delete this;
return f->bitwise_xor(p);
} else if(knumber_error *const p = dynamic_cast(rhs)) {
delete this;
return p->clone();
}
Q_ASSERT(0);
return nullptr;
}
//------------------------------------------------------------------------------
// Name: bitwise_or
//------------------------------------------------------------------------------
knumber_base *knumber_integer::bitwise_or(knumber_base *rhs) {
if(knumber_integer *const p = dynamic_cast(rhs)) {
mpz_ior(mpz_, mpz_, p->mpz_);
return this;
} else if(knumber_float *const p = dynamic_cast(rhs)) {
knumber_float *f = new knumber_float(this);
delete this;
return f->bitwise_or(p);
} else if(knumber_fraction *const p = dynamic_cast(rhs)) {
knumber_fraction *f = new knumber_fraction(this);
delete this;
return f->bitwise_or(p);
} else if(knumber_error *const p = dynamic_cast(rhs)) {
delete this;
return p->clone();
}
Q_ASSERT(0);
return nullptr;
}
//------------------------------------------------------------------------------
// Name: bitwise_shift
//------------------------------------------------------------------------------
knumber_base *knumber_integer::bitwise_shift(knumber_base *rhs) {
if(knumber_integer *const p = dynamic_cast(rhs)) {
const signed long int bit_count = mpz_get_si(p->mpz_);
// TODO: left shift with high bit set is broken in
// non decimal modes :-/, always displays 0
// interestingly, the bit is not "lost"
// we simply don't have a mechanism to display
// values in HEX/DEC/OCT mode which are greater than
// 64-bits
if(bit_count > 0) {
// left shift
mpz_mul_2exp(mpz_, mpz_, bit_count);
} else if(bit_count < 0) {
// right shift
if(mpz_sgn(mpz_) < 0) {
mpz_fdiv_q_2exp(mpz_, mpz_, -bit_count);
} else {
mpz_tdiv_q_2exp(mpz_, mpz_, -bit_count);
}
}
return this;
} else if(knumber_float *const p = dynamic_cast(rhs)) {
Q_UNUSED(p);
knumber_error *e = new knumber_error(knumber_error::ERROR_UNDEFINED);
delete this;
return e;
} else if(knumber_fraction *const p = dynamic_cast(rhs)) {
Q_UNUSED(p);
knumber_error *e = new knumber_error(knumber_error::ERROR_UNDEFINED);
delete this;
return e;
} else if(knumber_error *const p = dynamic_cast(rhs)) {
Q_UNUSED(p);
knumber_error *e = new knumber_error(knumber_error::ERROR_UNDEFINED);
delete this;
return e;
}
Q_ASSERT(0);
return nullptr;
}
//------------------------------------------------------------------------------
// Name: neg
//------------------------------------------------------------------------------
knumber_base *knumber_integer::neg() {
mpz_neg(mpz_, mpz_);
return this;
}
//------------------------------------------------------------------------------
// Name: cmp
//------------------------------------------------------------------------------
knumber_base *knumber_integer::cmp() {
#if 0
// unfortunately this breaks things pretty badly
// for non-decimal modes :-(
mpz_com(mpz_, mpz_);
#else
mpz_swap(mpz_, knumber_integer(~toUint64()).mpz_);
#endif
return this;
}
//------------------------------------------------------------------------------
// Name: abs
//------------------------------------------------------------------------------
knumber_base *knumber_integer::abs() {
mpz_abs(mpz_, mpz_);
return this;
}
//------------------------------------------------------------------------------
// Name: sqrt
//------------------------------------------------------------------------------
knumber_base *knumber_integer::sqrt() {
if(sign() < 0) {
delete this;
return new knumber_error(knumber_error::ERROR_UNDEFINED);
}
if(mpz_perfect_square_p(mpz_)) {
mpz_sqrt(mpz_, mpz_);
return this;
} else {
knumber_float *f = new knumber_float(this);
delete this;
return f->sqrt();
}
}
//------------------------------------------------------------------------------
// Name: cbrt
//------------------------------------------------------------------------------
knumber_base *knumber_integer::cbrt() {
mpz_t x;
mpz_init_set(x, mpz_);
if(mpz_root(x, x, 3)) {
mpz_swap(mpz_, x);
mpz_clear(x);
return this;
}
mpz_clear(x);
knumber_float *f = new knumber_float(this);
delete this;
return f->cbrt();
}
//------------------------------------------------------------------------------
// Name: pow
//------------------------------------------------------------------------------
knumber_base *knumber_integer::pow(knumber_base *rhs) {
if(knumber_integer *const p = dynamic_cast(rhs)) {
if(is_zero() && p->is_even() && p->sign() < 0) {
delete this;
return new knumber_error(knumber_error::ERROR_POS_INFINITY);
}
mpz_pow_ui(mpz_, mpz_, mpz_get_ui(p->mpz_));
if(p->sign() < 0) {
return reciprocal();
} else {
return this;
}
} else if(knumber_float *const p = dynamic_cast(rhs)) {
knumber_float *f = new knumber_float(this);
delete this;
return f->pow(p);
} else if(knumber_fraction *const p = dynamic_cast(rhs)) {
knumber_fraction *f = new knumber_fraction(this);
delete this;
return f->pow(p);
} else if(knumber_error *const p = dynamic_cast(rhs)) {
if(p->sign() > 0) {
knumber_error *e = new knumber_error(knumber_error::ERROR_POS_INFINITY);
delete this;
return e;
} else if(p->sign() < 0) {
mpz_init_set_si(mpz_, 0);
return this;
} else {
knumber_error *e = new knumber_error(knumber_error::ERROR_UNDEFINED);
delete this;
return e;
}
}
Q_ASSERT(0);
return nullptr;
}
//------------------------------------------------------------------------------
// Name: sin
//------------------------------------------------------------------------------
knumber_base *knumber_integer::sin() {
knumber_float *f = new knumber_float(this);
delete this;
return f->sin();
}
//------------------------------------------------------------------------------
// Name: cos
//------------------------------------------------------------------------------
knumber_base *knumber_integer::cos() {
knumber_float *f = new knumber_float(this);
delete this;
return f->cos();
}
//------------------------------------------------------------------------------
// Name: tan
//------------------------------------------------------------------------------
knumber_base *knumber_integer::tan() {
knumber_float *f = new knumber_float(this);
delete this;
return f->tan();
}
//------------------------------------------------------------------------------
// Name: asin
//------------------------------------------------------------------------------
knumber_base *knumber_integer::asin() {
knumber_float *f = new knumber_float(this);
delete this;
return f->asin();
}
//------------------------------------------------------------------------------
// Name: acos
//------------------------------------------------------------------------------
knumber_base *knumber_integer::acos() {
knumber_float *f = new knumber_float(this);
delete this;
return f->acos();
}
//------------------------------------------------------------------------------
// Name: atan
//------------------------------------------------------------------------------
knumber_base *knumber_integer::atan() {
knumber_float *f = new knumber_float(this);
delete this;
return f->atan();
}
//------------------------------------------------------------------------------
// Name: tgamma
//------------------------------------------------------------------------------
knumber_base *knumber_integer::tgamma() {
knumber_float *f = new knumber_float(this);
delete this;
return f->tgamma();
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_integer::sinh() {
knumber_float *f = new knumber_float(this);
delete this;
return f->sinh();
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_integer::cosh() {
knumber_float *f = new knumber_float(this);
delete this;
return f->cosh();
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_integer::tanh() {
knumber_float *f = new knumber_float(this);
delete this;
return f->tanh();
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_integer::asinh() {
knumber_float *f = new knumber_float(this);
delete this;
return f->asinh();
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_integer::acosh() {
knumber_float *f = new knumber_float(this);
delete this;
return f->acosh();
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
knumber_base *knumber_integer::atanh() {
knumber_float *f = new knumber_float(this);
delete this;
return f->atanh();
}
//------------------------------------------------------------------------------
// Name: factorial
//------------------------------------------------------------------------------
knumber_base *knumber_integer::factorial() {
if(sign() < 0) {
delete this;
return new knumber_error(knumber_error::ERROR_UNDEFINED);
}
mpz_fac_ui(mpz_, mpz_get_ui(mpz_));
return this;
}
//------------------------------------------------------------------------------
// Name: compare
//------------------------------------------------------------------------------
int knumber_integer::compare(knumber_base *rhs) {
if(knumber_integer *const p = dynamic_cast(rhs)) {
return mpz_cmp(mpz_, p->mpz_);
} else if(knumber_float *const p = dynamic_cast(rhs)) {
return knumber_float(this).compare(p);
} else if(knumber_fraction *const p = dynamic_cast(rhs)) {
return knumber_fraction(this).compare(p);
} else if(knumber_error *const p = dynamic_cast(rhs)) {
// NOTE: any number compared to NaN/Inf/-Inf always compares less
// at the moment
return -1;
}
Q_ASSERT(0);
return 0;
}
//------------------------------------------------------------------------------
// Name: toString
//------------------------------------------------------------------------------
QString knumber_integer::toString(int precision) const {
Q_UNUSED(precision);
const size_t size = gmp_snprintf(nullptr, 0, "%Zd", mpz_) + 1;
QScopedArrayPointer buf(new char[size]);
gmp_snprintf(&buf[0], size, "%Zd", mpz_);
return QLatin1String(&buf[0]);
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
quint64 knumber_integer::toUint64() const {
// libgmp doesn't have unsigned long long conversion
// so convert to string and then to unsigned long long
const QString tmpstring = toString(-1);
bool ok;
quint64 value;
if (sign() < 0) {
const qint64 signedvalue = tmpstring.toLongLong(&ok, 10);
value = static_cast(signedvalue);
} else {
value = tmpstring.toULongLong(&ok, 10);
}
if (!ok) {
// TODO: what to do if error?
value = 0;
}
return value;
}
//------------------------------------------------------------------------------
// Name:
//------------------------------------------------------------------------------
qint64 knumber_integer::toInt64() const {
// libgmp doesn't have long long conversion
// so convert to string and then to long long
const QString tmpstring = toString(-1);
bool ok;
qint64 value = tmpstring.toLongLong(&ok, 10);
if (!ok) {
// TODO: what to do if error?
value = 0;
}
return value;
}
//------------------------------------------------------------------------------
// Name: is_integer
//------------------------------------------------------------------------------
bool knumber_integer::is_integer() const {
return true;
}
//------------------------------------------------------------------------------
// Name: is_zero
//------------------------------------------------------------------------------
bool knumber_integer::is_zero() const {
return mpz_sgn(mpz_) == 0;
}
//------------------------------------------------------------------------------
// Name: sign
//------------------------------------------------------------------------------
int knumber_integer::sign() const {
return mpz_sgn(mpz_);
}
//------------------------------------------------------------------------------
// Name: is_even
//------------------------------------------------------------------------------
bool knumber_integer::is_even() const {
return mpz_even_p(mpz_);
}
//------------------------------------------------------------------------------
// Name: is_odd
//------------------------------------------------------------------------------
bool knumber_integer::is_odd() const {
return mpz_odd_p(mpz_);
}
//------------------------------------------------------------------------------
// Name: reciprocal
//------------------------------------------------------------------------------
knumber_base *knumber_integer::reciprocal() {
knumber_fraction *q = new knumber_fraction(this);
delete this;
return q->reciprocal();
}
//------------------------------------------------------------------------------
// Name: log2
//------------------------------------------------------------------------------
knumber_base *knumber_integer::log2() {
knumber_float *f = new knumber_float(this);
delete this;
return f->log2();
}
//------------------------------------------------------------------------------
// Name: floor
//------------------------------------------------------------------------------
knumber_base *knumber_integer::floor() {
// should have no effect on the value
return this;
}
//------------------------------------------------------------------------------
// Name: ceil
//------------------------------------------------------------------------------
knumber_base *knumber_integer::ceil() {
// should have no effect on the value
return this;
}
//------------------------------------------------------------------------------
// Name: log10
//------------------------------------------------------------------------------
knumber_base *knumber_integer::log10() {
knumber_float *f = new knumber_float(this);
delete this;
return f->log10();
}
//------------------------------------------------------------------------------
// Name: ln
//------------------------------------------------------------------------------
knumber_base *knumber_integer::ln() {
knumber_float *f = new knumber_float(this);
delete this;
return f->ln();
}
//------------------------------------------------------------------------------
// Name: exp2
//------------------------------------------------------------------------------
knumber_base *knumber_integer::exp2() {
knumber_float *f = new knumber_float(this);
delete this;
return f->exp2();
}
//------------------------------------------------------------------------------
// Name: exp10
//------------------------------------------------------------------------------
knumber_base *knumber_integer::exp10() {
knumber_float *f = new knumber_float(this);
delete this;
return f->exp10();
}
//------------------------------------------------------------------------------
// Name: exp
//------------------------------------------------------------------------------
knumber_base *knumber_integer::exp() {
knumber_float *f = new knumber_float(this);
delete this;
return f->exp();
}
//------------------------------------------------------------------------------
// Name: bin
//------------------------------------------------------------------------------
knumber_base *knumber_integer::bin(knumber_base *rhs) {
if(knumber_integer *const p = dynamic_cast(rhs)) {
mpz_bin_ui(mpz_, mpz_, mpz_get_ui(p->mpz_));
return this;
} else if(knumber_float *const p = dynamic_cast(rhs)) {
delete this;
return new knumber_error(knumber_error::ERROR_UNDEFINED);
} else if(knumber_fraction *const p = dynamic_cast(rhs)) {
delete this;
return new knumber_error(knumber_error::ERROR_UNDEFINED);
} else if(knumber_error *const p = dynamic_cast(rhs)) {
delete this;
return new knumber_error(knumber_error::ERROR_UNDEFINED);
}
Q_ASSERT(0);
return nullptr;
}
}
diff --git a/knumber/tests/CMakeLists.txt b/knumber/tests/CMakeLists.txt
index c961f11..9cc7eb0 100644
--- a/knumber/tests/CMakeLists.txt
+++ b/knumber/tests/CMakeLists.txt
@@ -1,9 +1,10 @@
include_directories( ${CMAKE_SOURCE_DIR}/knumber )
include(ECMAddTests)
+list(APPEND knumbertest_LIBS Qt5::Core ${MPFR_LIBRARIES} ${GMP_LIBRARIES})
+
ecm_add_test(knumbertest.cpp ${libknumber_la_SRCS}
- LINK_LIBRARIES Qt5::Core ${GMP_LIBRARIES}
+ LINK_LIBRARIES ${knumbertest_LIBS}
TEST_NAME knumbertest
)
-