AbaKus – a complex calculator
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

205 lines
5.1 KiB

/*
* 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 <kglobal.h>
#include <klocale.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 */
// vim: set et ts=8 sw=4: