mirror of
https://bitbucket.org/smil3y/kde-extraapps.git
synced 2025-02-24 19:02:53 +00:00
1028 lines
28 KiB
C++
1028 lines
28 KiB
C++
/*
|
|
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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <config-kcalc.h>
|
|
#include "knumber_integer.h"
|
|
#include "knumber_float.h"
|
|
#include "knumber_fraction.h"
|
|
#include "knumber_error.h"
|
|
#include <QScopedArrayPointer>
|
|
#include <QDebug>
|
|
#include <math.h>
|
|
|
|
#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 <double F(double)>
|
|
knumber_base *knumber_float::execute_libc_func(double x) {
|
|
const double r = F(x);
|
|
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 <double F(double, double)>
|
|
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;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name:
|
|
//------------------------------------------------------------------------------
|
|
knumber_float::knumber_float(const QString &s) {
|
|
|
|
mpf_init(mpf_);
|
|
mpf_set_str(mpf_, s.toAscii(), 10);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name:
|
|
//------------------------------------------------------------------------------
|
|
knumber_float::knumber_float(double value) {
|
|
|
|
Q_ASSERT(!isinf(value));
|
|
Q_ASSERT(!isnan(value));
|
|
|
|
mpf_init_set_d(mpf_, value);
|
|
}
|
|
|
|
#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);
|
|
}
|
|
#endif
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name:
|
|
//------------------------------------------------------------------------------
|
|
knumber_float::knumber_float(mpf_t mpf) {
|
|
|
|
mpf_init(mpf_);
|
|
mpf_set(mpf_, mpf);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name:
|
|
//------------------------------------------------------------------------------
|
|
knumber_float::knumber_float(const knumber_float *value) {
|
|
|
|
mpf_init_set(mpf_, value->mpf_);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name:
|
|
//------------------------------------------------------------------------------
|
|
knumber_float::knumber_float(const knumber_integer *value) {
|
|
|
|
mpf_init(mpf_);
|
|
mpf_set_z(mpf_, value->mpz_);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name:
|
|
//------------------------------------------------------------------------------
|
|
knumber_float::knumber_float(const knumber_fraction *value) {
|
|
|
|
mpf_init(mpf_);
|
|
mpf_set_q(mpf_, value->mpq_);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name:
|
|
//------------------------------------------------------------------------------
|
|
knumber_base *knumber_float::clone() {
|
|
|
|
return new knumber_float(this);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name:
|
|
//------------------------------------------------------------------------------
|
|
knumber_float::~knumber_float() {
|
|
|
|
mpf_clear(mpf_);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name:
|
|
//------------------------------------------------------------------------------
|
|
knumber_base *knumber_float::add(knumber_base *rhs) {
|
|
|
|
if(knumber_integer *const p = dynamic_cast<knumber_integer *>(rhs)) {
|
|
knumber_float f(p);
|
|
return add(&f);
|
|
} else if(knumber_float *const p = dynamic_cast<knumber_float *>(rhs)) {
|
|
mpf_add(mpf_, mpf_, p->mpf_);
|
|
return this;
|
|
} else if(knumber_fraction *const p = dynamic_cast<knumber_fraction *>(rhs)) {
|
|
knumber_float f(p);
|
|
return add(&f);
|
|
} else if(knumber_error *const p = dynamic_cast<knumber_error *>(rhs)) {
|
|
knumber_error *e = new knumber_error(p);
|
|
delete this;
|
|
return e;
|
|
}
|
|
|
|
Q_ASSERT(0);
|
|
return 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name:
|
|
//------------------------------------------------------------------------------
|
|
knumber_base *knumber_float::sub(knumber_base *rhs) {
|
|
|
|
if(knumber_integer *const p = dynamic_cast<knumber_integer *>(rhs)) {
|
|
knumber_float f(p);
|
|
return sub(&f);
|
|
} else if(knumber_float *const p = dynamic_cast<knumber_float *>(rhs)) {
|
|
mpf_sub(mpf_, mpf_, p->mpf_);
|
|
return this;
|
|
} else if(knumber_fraction *const p = dynamic_cast<knumber_fraction *>(rhs)) {
|
|
knumber_float f(p);
|
|
return sub(&f);
|
|
} else if(knumber_error *const p = dynamic_cast<knumber_error *>(rhs)) {
|
|
knumber_error *e = new knumber_error(p);
|
|
delete this;
|
|
return e->neg();
|
|
}
|
|
|
|
Q_ASSERT(0);
|
|
return 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name:
|
|
//------------------------------------------------------------------------------
|
|
knumber_base *knumber_float::mul(knumber_base *rhs) {
|
|
|
|
if(knumber_integer *const p = dynamic_cast<knumber_integer *>(rhs)) {
|
|
knumber_float f(p);
|
|
return mul(&f);
|
|
} else if(knumber_float *const p = dynamic_cast<knumber_float *>(rhs)) {
|
|
mpf_mul(mpf_, mpf_, p->mpf_);
|
|
return this;
|
|
} else if(knumber_fraction *const p = dynamic_cast<knumber_fraction *>(rhs)) {
|
|
knumber_float f(p);
|
|
return mul(&f);
|
|
} else if(knumber_error *const p = dynamic_cast<knumber_error *>(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 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// 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<knumber_integer *>(rhs)) {
|
|
knumber_float f(p);
|
|
return div(&f);
|
|
} else if(knumber_float *const p = dynamic_cast<knumber_float *>(rhs)) {
|
|
mpf_div(mpf_, mpf_, p->mpf_);
|
|
return this;
|
|
} else if(knumber_fraction *const p = dynamic_cast<knumber_fraction *>(rhs)) {
|
|
knumber_float f(p);
|
|
return div(&f);
|
|
} else if(knumber_error *const p = dynamic_cast<knumber_error *>(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 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// 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_);
|
|
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_);
|
|
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
|
|
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;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// 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
|
|
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// 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
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// 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
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
// 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
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// 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
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name:
|
|
//------------------------------------------------------------------------------
|
|
knumber_base *knumber_float::asin() {
|
|
if(mpf_cmp_d(mpf_, 1.0) > 0 || mpf_cmp_d(mpf_, -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
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name:
|
|
//------------------------------------------------------------------------------s
|
|
knumber_base *knumber_float::acos() {
|
|
if(mpf_cmp_d(mpf_, 1.0) > 0 || mpf_cmp_d(mpf_, -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
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// 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
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// 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
|
|
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// 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
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// 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
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// 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
|
|
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// 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
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// 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
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// 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
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name:
|
|
//------------------------------------------------------------------------------
|
|
knumber_base *knumber_float::pow(knumber_base *rhs) {
|
|
|
|
if(knumber_integer *const p = dynamic_cast<knumber_integer *>(rhs)) {
|
|
mpf_pow_ui(mpf_, mpf_, mpz_get_ui(p->mpz_));
|
|
|
|
if(p->sign() < 0) {
|
|
return reciprocal();
|
|
} else {
|
|
return this;
|
|
}
|
|
} else if(knumber_float *const p = dynamic_cast<knumber_float *>(rhs)) {
|
|
return execute_libc_func< ::pow>(mpf_get_d(mpf_), mpf_get_d(p->mpf_));
|
|
} else if(knumber_fraction *const p = dynamic_cast<knumber_fraction *>(rhs)) {
|
|
knumber_float f(p);
|
|
return execute_libc_func< ::pow>(mpf_get_d(mpf_), mpf_get_d(f.mpf_));
|
|
} else if(knumber_error *const p = dynamic_cast<knumber_error *>(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 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name:
|
|
//------------------------------------------------------------------------------
|
|
int knumber_float::compare(knumber_base *rhs) {
|
|
|
|
if(knumber_integer *const p = dynamic_cast<knumber_integer *>(rhs)) {
|
|
knumber_float f(p);
|
|
return compare(&f);
|
|
} else if(knumber_float *const p = dynamic_cast<knumber_float *>(rhs)) {
|
|
return mpf_cmp(mpf_, p->mpf_);
|
|
} else if(knumber_fraction *const p = dynamic_cast<knumber_fraction *>(rhs)) {
|
|
knumber_float f(p);
|
|
return compare(&f);
|
|
} else if(knumber_error *const p = dynamic_cast<knumber_error *>(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(NULL, 0, "%.*Fg", precision, mpf_) + 1;
|
|
} else {
|
|
size = gmp_snprintf(NULL, 0, "%.Fg", mpf_) + 1;
|
|
}
|
|
|
|
QScopedArrayPointer<char> buf(new char[size]);
|
|
|
|
if (precision > 0) {
|
|
gmp_snprintf(&buf[0], size, "%.*Fg", precision, mpf_);
|
|
} else {
|
|
gmp_snprintf(&buf[0], size, "%.Fg", mpf_);
|
|
}
|
|
|
|
return QLatin1String(&buf[0]);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name:
|
|
//------------------------------------------------------------------------------
|
|
bool knumber_float::is_integer() const {
|
|
|
|
return mpf_integer_p(mpf_) != 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name:
|
|
//------------------------------------------------------------------------------
|
|
bool knumber_float::is_zero() const {
|
|
|
|
return mpf_sgn(mpf_) == 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name:
|
|
//------------------------------------------------------------------------------
|
|
int knumber_float::sign() const {
|
|
|
|
return mpf_sgn(mpf_);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Name:
|
|
//------------------------------------------------------------------------------
|
|
knumber_base *knumber_float::reciprocal() {
|
|
|
|
mpf_t mpf;
|
|
mpf_init_set_d(mpf, 1.0);
|
|
mpf_div(mpf_, mpf, mpf_);
|
|
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
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// 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
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// 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
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// 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
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// 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
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// 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
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// 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);
|
|
}
|
|
|
|
}
|