You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
204 lines
5.1 KiB
C++
204 lines
5.1 KiB
C++
/*
|
|
* numerictypes.cpp - part of abakus
|
|
* Copyright (C) 2004, 2005 Michael Pyne <michael.pyne@kdemail.net>
|
|
*
|
|
* 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, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include "numerictypes.h"
|
|
#include "hmath.h"
|
|
|
|
#include <kdebug.h>
|
|
#include <tdeglobal.h>
|
|
#include <tdelocale.h>
|
|
|
|
Abakus::TrigMode Abakus::m_trigMode = Abakus::Degrees;
|
|
int Abakus::m_prec = -1;
|
|
|
|
#if HAVE_MPFR
|
|
|
|
namespace Abakus
|
|
{
|
|
|
|
TQString convertToString(const mpfr_ptr &number)
|
|
{
|
|
char *str = 0;
|
|
TQRegExp zeroKiller ("0*$");
|
|
mp_exp_t exp;
|
|
int desiredPrecision = Abakus::m_prec;
|
|
TQString decimalSymbol = TDEGlobal::locale()->decimalSymbol();
|
|
|
|
if(desiredPrecision < 0)
|
|
desiredPrecision = 8;
|
|
|
|
// This first call is to see approximately how many digits of precision
|
|
// the fractional part has.
|
|
str = mpfr_get_str (0, &exp, 10, desiredPrecision, number, GMP_RNDN);
|
|
|
|
// Check for ginormously small numbers.
|
|
if(exp < -74)
|
|
return "0";
|
|
|
|
if(exp < -2 || exp > desiredPrecision)
|
|
{
|
|
// Use exponential notation.
|
|
TQString numbers (str);
|
|
mpfr_free_str(str);
|
|
|
|
TQString sign, l, r;
|
|
if(numbers[0] == '-')
|
|
{
|
|
sign = "-";
|
|
l = numbers[1];
|
|
r = numbers.right(numbers.length() - 2);
|
|
}
|
|
else
|
|
{
|
|
l = numbers[0];
|
|
r = numbers.right(numbers.length() - 1);
|
|
}
|
|
|
|
// Remove trailing zeroes.
|
|
if(Abakus::m_prec < 0)
|
|
r.replace(zeroKiller, "");
|
|
|
|
// But don't display numbers like 2.e10 either.
|
|
if(r.isEmpty())
|
|
r = "0";
|
|
|
|
r.append(TQString("e%1").arg(exp - 1));
|
|
|
|
return sign + l + decimalSymbol + r;
|
|
}
|
|
else
|
|
{
|
|
mpfr_free_str(str);
|
|
|
|
// This call is to adjust the result so that the fractional part has at
|
|
// most m_prec digits of precision.
|
|
str = mpfr_get_str (0, &exp, 10, exp + desiredPrecision, number, GMP_RNDN);
|
|
}
|
|
|
|
TQString result = str;
|
|
mpfr_free_str(str);
|
|
str = 0;
|
|
|
|
int position = exp;
|
|
TQString l, r, sign;
|
|
|
|
if(position < 0) { // Number < 0.1
|
|
l.fill('0', -position);
|
|
|
|
if(result[0] == '-') {
|
|
sign = "-";
|
|
r = result.right(result.length() - 1);
|
|
}
|
|
else
|
|
r = result;
|
|
|
|
r = l + r;
|
|
l = '0';
|
|
}
|
|
else { // Number >= 0.1
|
|
if(result[0] == '-') {
|
|
l = result.mid(1, position);
|
|
sign = "-";
|
|
position++;
|
|
}
|
|
else
|
|
l = result.left(position);
|
|
|
|
r = result.right(result.length() - position);
|
|
}
|
|
|
|
// Remove trailing zeroes.
|
|
r.replace(zeroKiller, "");
|
|
|
|
// Don't display numbers of the form .23
|
|
if(l.isEmpty())
|
|
l = "0";
|
|
|
|
// If we have an integer don't display the decimal part.
|
|
if(r.isEmpty())
|
|
return sign + l;
|
|
|
|
return sign + l + decimalSymbol + r;
|
|
}
|
|
|
|
} // namespace Abakus
|
|
|
|
Abakus::number_t::value_type setupPi()
|
|
{
|
|
static mpfr_t pi;
|
|
|
|
mpfr_init2 (pi, 250);
|
|
mpfr_const_pi (pi, GMP_RNDN);
|
|
|
|
return pi;
|
|
}
|
|
|
|
Abakus::number_t::value_type setupExponential()
|
|
{
|
|
static mpfr_t exponential;
|
|
mpfr_t one;
|
|
|
|
mpfr_init2 (exponential, 250);
|
|
mpfr_init_set_ui (one, 1, GMP_RNDN);
|
|
mpfr_exp (exponential, one, GMP_RNDN);
|
|
mpfr_clear (one);
|
|
|
|
return exponential;
|
|
}
|
|
|
|
const Abakus::number_t::value_type Abakus::number_t::PI = setupPi();
|
|
const Abakus::number_t::value_type Abakus::number_t::E = setupExponential();
|
|
|
|
#else
|
|
|
|
// Converts hmath number to a string.
|
|
|
|
namespace Abakus
|
|
{
|
|
|
|
TQString convertToString(const HNumber &num)
|
|
{
|
|
TQString str = HMath::formatGenString(num, m_prec);
|
|
TQString decimalSymbol = TDEGlobal::locale()->decimalSymbol();
|
|
str.replace('.', decimalSymbol);
|
|
|
|
TQStringList parts = TQStringList::split("e", str);
|
|
TQRegExp zeroKiller("(" + TQRegExp::escape(decimalSymbol) +
|
|
"\\d*[1-9])0*$"); // Remove trailing zeroes.
|
|
TQRegExp zeroKiller2("(" + TQRegExp::escape(decimalSymbol) + ")0*$");
|
|
|
|
str = parts[0];
|
|
str.replace(zeroKiller, "\\1");
|
|
str.replace(zeroKiller2, "\\1");
|
|
if(str.endsWith(decimalSymbol))
|
|
str.truncate(str.length() - 1); // Remove trailing period.
|
|
|
|
if(parts.count() > 1 && parts[1] != "0")
|
|
str += TQString("e%1").arg(parts[1]);
|
|
|
|
return str;
|
|
}
|
|
|
|
} // namespace Abakus.
|
|
|
|
const Abakus::number_t::value_type Abakus::number_t::PI = HMath::pi();
|
|
const Abakus::number_t::value_type Abakus::number_t::E = HMath::exp(1);
|
|
|
|
#endif /* HAVE_MPFR */
|