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.
 
 
 
 
 

206 lines
5.1 KiB

  1. /*
  2. * numerictypes.cpp - part of abakus
  3. * Copyright (C) 2004, 2005 Michael Pyne <michael.pyne@kdemail.net>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  18. */
  19. #include "numerictypes.h"
  20. #include "hmath.h"
  21. #include <kdebug.h>
  22. #include <kglobal.h>
  23. #include <klocale.h>
  24. Abakus::TrigMode Abakus::m_trigMode = Abakus::Degrees;
  25. int Abakus::m_prec = -1;
  26. #if HAVE_MPFR
  27. namespace Abakus
  28. {
  29. TQString convertToString(const mpfr_ptr &number)
  30. {
  31. char *str = 0;
  32. TQRegExp zeroKiller ("0*$");
  33. mp_exp_t exp;
  34. int desiredPrecision = Abakus::m_prec;
  35. TQString decimalSymbol = TDEGlobal::locale()->decimalSymbol();
  36. if(desiredPrecision < 0)
  37. desiredPrecision = 8;
  38. // This first call is to see approximately how many digits of precision
  39. // the fractional part has.
  40. str = mpfr_get_str (0, &exp, 10, desiredPrecision, number, GMP_RNDN);
  41. // Check for ginormously small numbers.
  42. if(exp < -74)
  43. return "0";
  44. if(exp < -2 || exp > desiredPrecision)
  45. {
  46. // Use exponential notation.
  47. TQString numbers (str);
  48. mpfr_free_str(str);
  49. TQString sign, l, r;
  50. if(numbers[0] == '-')
  51. {
  52. sign = "-";
  53. l = numbers[1];
  54. r = numbers.right(numbers.length() - 2);
  55. }
  56. else
  57. {
  58. l = numbers[0];
  59. r = numbers.right(numbers.length() - 1);
  60. }
  61. // Remove trailing zeroes.
  62. if(Abakus::m_prec < 0)
  63. r.replace(zeroKiller, "");
  64. // But don't display numbers like 2.e10 either.
  65. if(r.isEmpty())
  66. r = "0";
  67. r.append(TQString("e%1").arg(exp - 1));
  68. return sign + l + decimalSymbol + r;
  69. }
  70. else
  71. {
  72. mpfr_free_str(str);
  73. // This call is to adjust the result so that the fractional part has at
  74. // most m_prec digits of precision.
  75. str = mpfr_get_str (0, &exp, 10, exp + desiredPrecision, number, GMP_RNDN);
  76. }
  77. TQString result = str;
  78. mpfr_free_str(str);
  79. str = 0;
  80. int position = exp;
  81. TQString l, r, sign;
  82. if(position < 0) { // Number < 0.1
  83. l.fill('0', -position);
  84. if(result[0] == '-') {
  85. sign = "-";
  86. r = result.right(result.length() - 1);
  87. }
  88. else
  89. r = result;
  90. r = l + r;
  91. l = '0';
  92. }
  93. else { // Number >= 0.1
  94. if(result[0] == '-') {
  95. l = result.mid(1, position);
  96. sign = "-";
  97. position++;
  98. }
  99. else
  100. l = result.left(position);
  101. r = result.right(result.length() - position);
  102. }
  103. // Remove trailing zeroes.
  104. r.replace(zeroKiller, "");
  105. // Don't display numbers of the form .23
  106. if(l.isEmpty())
  107. l = "0";
  108. // If we have an integer don't display the decimal part.
  109. if(r.isEmpty())
  110. return sign + l;
  111. return sign + l + decimalSymbol + r;
  112. }
  113. } // namespace Abakus
  114. Abakus::number_t::value_type setupPi()
  115. {
  116. static mpfr_t pi;
  117. mpfr_init2 (pi, 250);
  118. mpfr_const_pi (pi, GMP_RNDN);
  119. return pi;
  120. }
  121. Abakus::number_t::value_type setupExponential()
  122. {
  123. static mpfr_t exponential;
  124. mpfr_t one;
  125. mpfr_init2 (exponential, 250);
  126. mpfr_init_set_ui (one, 1, GMP_RNDN);
  127. mpfr_exp (exponential, one, GMP_RNDN);
  128. mpfr_clear (one);
  129. return exponential;
  130. }
  131. const Abakus::number_t::value_type Abakus::number_t::PI = setupPi();
  132. const Abakus::number_t::value_type Abakus::number_t::E = setupExponential();
  133. #else
  134. // Converts hmath number to a string.
  135. namespace Abakus
  136. {
  137. TQString convertToString(const HNumber &num)
  138. {
  139. TQString str = HMath::formatGenString(num, m_prec);
  140. TQString decimalSymbol = TDEGlobal::locale()->decimalSymbol();
  141. str.replace('.', decimalSymbol);
  142. TQStringList parts = TQStringList::split("e", str);
  143. TQRegExp zeroKiller("(" + TQRegExp::escape(decimalSymbol) +
  144. "\\d*[1-9])0*$"); // Remove trailing zeroes.
  145. TQRegExp zeroKiller2("(" + TQRegExp::escape(decimalSymbol) + ")0*$");
  146. str = parts[0];
  147. str.replace(zeroKiller, "\\1");
  148. str.replace(zeroKiller2, "\\1");
  149. if(str.endsWith(decimalSymbol))
  150. str.truncate(str.length() - 1); // Remove trailing period.
  151. if(parts.count() > 1 && parts[1] != "0")
  152. str += TQString("e%1").arg(parts[1]);
  153. return str;
  154. }
  155. } // namespace Abakus.
  156. const Abakus::number_t::value_type Abakus::number_t::PI = HMath::pi();
  157. const Abakus::number_t::value_type Abakus::number_t::E = HMath::exp(1);
  158. #endif /* HAVE_MPFR */
  159. // vim: set et ts=8 sw=4: