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.

299 lines
8.3KB

  1. /*
  2. * function.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 <kdebug.h>
  21. #include <tqvaluevector.h>
  22. #include <tqstring.h>
  23. #include <tqregexp.h>
  24. #include <math.h>
  25. #include "function.h"
  26. #include "node.h"
  27. #include "valuemanager.h"
  28. #include "hmath.h"
  29. // Used to try and avoid recursive function definitions
  30. class DupFinder : public NodeFunctor
  31. {
  32. public:
  33. DupFinder(const TQString &nameToFind) :
  34. m_name(nameToFind), m_valid(true)
  35. {
  36. }
  37. virtual ~DupFinder() { }
  38. bool isValid() const { return m_valid; }
  39. virtual void operator()(const Node *node)
  40. {
  41. if(!m_valid)
  42. return;
  43. const BaseFunction *fn = dynamic_cast<const BaseFunction *>(node);
  44. if(fn && fn->name() == m_name)
  45. m_valid = false; // Duplicate detected
  46. }
  47. private:
  48. TQString m_name;
  49. bool m_valid;
  50. };
  51. // Define static member for FunctionManager
  52. FunctionManager *FunctionManager::m_manager = 0;
  53. FunctionManager *FunctionManager::instance()
  54. {
  55. if(!m_manager)
  56. m_manager = new FunctionManager;
  57. return m_manager;
  58. }
  59. FunctionManager::FunctionManager(TQObject *parent, const char *name) :
  60. TQObject(parent, name)
  61. {
  62. m_dict.setAutoDelete(true);
  63. }
  64. // Dummy return value to enable static initialization in the DECL_*()
  65. // macros.
  66. bool FunctionManager::addFunction(const TQString &name, function_t fn, const TQString &desc)
  67. {
  68. Function *newFn = new Function;
  69. TQRegExp returnTrigRE("^a(cos|sin|tan)");
  70. TQRegExp needsTrigRE("^(cos|sin|tan)");
  71. TQString fnName(name);
  72. newFn->name = name;
  73. newFn->description = desc;
  74. newFn->fn = fn;
  75. newFn->userDefined = false;
  76. newFn->returnsTrig = fnName.contains(returnTrigRE);
  77. newFn->needsTrig = fnName.contains(needsTrigRE);
  78. m_dict.insert(name, newFn);
  79. return false;
  80. }
  81. #define DECLARE_FUNC(name, fn, desc) bool dummy##name = FunctionManager::instance()->addFunction(#name, fn, desc)
  82. // Declares a function name that is implemented by the function of a different
  83. // name. e.g. atan -> Abakus::number_t::arctan()
  84. #define DECLARE_FUNC2(name, fnName, desc) DECLARE_FUNC(name, &Abakus::number_t::fnName, desc)
  85. // Declares a function name that is implemented by the function of the
  86. // same base name.
  87. #define DECLARE_FUNC1(name, desc) DECLARE_FUNC2(name, name, desc)
  88. DECLARE_FUNC1(sin, "Trigonometric sine");
  89. DECLARE_FUNC1(cos, "Trigonometric cosine");
  90. DECLARE_FUNC1(tan, "Trigonometric tangent");
  91. DECLARE_FUNC1(sinh, "Hyperbolic sine");
  92. DECLARE_FUNC1(cosh, "Hyperbolic cosine");
  93. DECLARE_FUNC1(tanh, "Hyperbolic tangent");
  94. DECLARE_FUNC1(atan, "Inverse tangent");
  95. DECLARE_FUNC1(acos, "Inverse cosine");
  96. DECLARE_FUNC1(asin, "Inverse sine");
  97. DECLARE_FUNC1(asinh, "Inverse hyperbolic sine");
  98. DECLARE_FUNC1(acosh, "Inverse hyperbolic cosine");
  99. DECLARE_FUNC1(atanh, "Inverse hyperbolic tangent");
  100. DECLARE_FUNC1(abs, "Absolute value of number");
  101. DECLARE_FUNC1(sqrt, "Square root");
  102. DECLARE_FUNC1(ln, "Natural logarithm (base e)");
  103. DECLARE_FUNC1(log, "Logarithm (base 10)");
  104. DECLARE_FUNC1(exp, "Natural exponential function");
  105. DECLARE_FUNC1(round, "Round to nearest number");
  106. DECLARE_FUNC1(ceil, "Nearest greatest integer");
  107. DECLARE_FUNC1(floor, "Nearest lesser integer");
  108. DECLARE_FUNC2(int, integer, "Integral part of number");
  109. DECLARE_FUNC1(frac, "Fractional part of number");
  110. Function *FunctionManager::function(const TQString &name)
  111. {
  112. return m_dict[name];
  113. }
  114. // Returns true if the named identifier is a function, false otherwise.
  115. bool FunctionManager::isFunction(const TQString &name)
  116. {
  117. return function(name) != 0;
  118. }
  119. bool FunctionManager::isFunctionUserDefined(const TQString &name)
  120. {
  121. const Function *fn = function(name);
  122. return (fn != 0) && (fn->userDefined);
  123. }
  124. bool FunctionManager::addFunction(BaseFunction *fn, const TQString &dependantVar)
  125. {
  126. // First see if this function is recursive
  127. DupFinder dupFinder(fn->name());
  128. UnaryFunction *unFunction = dynamic_cast<UnaryFunction *>(fn);
  129. if(unFunction && unFunction->operand()) {
  130. unFunction->operand()->applyMap(dupFinder);
  131. if(!dupFinder.isValid())
  132. return false;
  133. }
  134. // Structure holds extra data needed to call the user defined
  135. // function.
  136. UserFunction *newFn = new UserFunction;
  137. newFn->sequenceNumber = m_dict.count();
  138. newFn->fn = fn;
  139. newFn->varName = TQString(dependantVar);
  140. // Now setup the Function data structure that holds the information
  141. // we need to access and call the function later.
  142. Function *fnTabEntry = new Function;
  143. fnTabEntry->name = fn->name();
  144. fnTabEntry->userFn = newFn;
  145. fnTabEntry->returnsTrig = false;
  146. fnTabEntry->needsTrig = false;
  147. fnTabEntry->userDefined = true;
  148. if(m_dict.find(fn->name()))
  149. emit signalFunctionRemoved(fn->name());
  150. m_dict.replace(fn->name(), fnTabEntry);
  151. emit signalFunctionAdded(fn->name());
  152. return true;
  153. }
  154. void FunctionManager::removeFunction(const TQString &name)
  155. {
  156. Function *fn = function(name);
  157. // If we remove a function, we need to decrement the sequenceNumber of
  158. // functions after this one.
  159. if(fn && fn->userDefined) {
  160. int savedSeqNum = fn->userFn->sequenceNumber;
  161. // Emit before we actually remove it so that the info on the function
  162. // can still be looked up.
  163. emit signalFunctionRemoved(name);
  164. delete fn->userFn;
  165. fn->userFn = 0;
  166. m_dict.remove(name);
  167. TQDictIterator<Function> it(m_dict);
  168. for (; it.current(); ++it) {
  169. UserFunction *userFn = it.current()->userDefined ? it.current()->userFn : 0;
  170. if(userFn && userFn->sequenceNumber > savedSeqNum)
  171. --it.current()->userFn->sequenceNumber;
  172. }
  173. }
  174. }
  175. TQStringList FunctionManager::functionList(FunctionManager::FunctionType type)
  176. {
  177. TQDictIterator<Function> it(m_dict);
  178. TQStringList functions;
  179. switch(type) {
  180. case Builtin:
  181. for(; it.current(); ++it)
  182. if(!it.current()->userDefined)
  183. functions += it.current()->name;
  184. break;
  185. case UserDefined:
  186. // We want to return the function names in the order they were
  187. // added.
  188. {
  189. TQValueVector<Function *> fnTable(m_dict.count(), 0);
  190. TQValueVector<int> sequenceNumberTable(m_dict.count(), -1);
  191. // First find out what sequence numbers we have.
  192. for(; it.current(); ++it)
  193. if(it.current()->userDefined) {
  194. int id = it.current()->userFn->sequenceNumber;
  195. fnTable[id] = it.current();
  196. sequenceNumberTable.append(id);
  197. }
  198. // Now sort the sequence numbers and return the ordered list
  199. qHeapSort(sequenceNumberTable.begin(), sequenceNumberTable.end());
  200. for(unsigned i = 0; i < sequenceNumberTable.count(); ++i)
  201. if(sequenceNumberTable[i] >= 0)
  202. functions += fnTable[sequenceNumberTable[i]]->name;
  203. }
  204. break;
  205. case All:
  206. functions += functionList(Builtin);
  207. functions += functionList(UserDefined);
  208. break;
  209. }
  210. return functions;
  211. }
  212. // Applies the function identified by func, using value as a parameter.
  213. Abakus::number_t evaluateFunction(const Function *func, const Abakus::number_t value)
  214. {
  215. if(func->userDefined) {
  216. // Pull real entry from userFunctionTable
  217. UserFunction *realFunction = func->userFn;
  218. bool wasSet = ValueManager::instance()->isValueSet(realFunction->varName);
  219. Abakus::number_t oldValue;
  220. if(wasSet)
  221. oldValue = ValueManager::instance()->value(realFunction->varName);
  222. ValueManager::instance()->setValue(realFunction->varName, value);
  223. Abakus::number_t result = realFunction->fn->value();
  224. if(wasSet)
  225. ValueManager::instance()->setValue(realFunction->varName, oldValue);
  226. else
  227. ValueManager::instance()->removeValue(realFunction->varName);
  228. return result;
  229. }
  230. return (value.*(func->fn))();
  231. }
  232. void setTrigMode(Abakus::TrigMode mode)
  233. {
  234. Abakus::m_trigMode = mode;
  235. }
  236. Abakus::TrigMode trigMode()
  237. {
  238. return Abakus::m_trigMode;
  239. }
  240. #include "function.moc"