diff options
author | Reinier Heeres <reinier@heeres.eu> | 2007-11-18 19:34:59 (GMT) |
---|---|---|
committer | Reinier Heeres <reinier@heeres.eu> | 2007-11-18 19:34:59 (GMT) |
commit | f8a8343c92f8ab54614660c235c6e6c18e5464db (patch) | |
tree | c61d024118ce3dc7ca3da8b9e210a65601b9f6e6 | |
parent | 29e05573dd8f69fe474433dac8873fab7aeda6f0 (diff) |
Included support for rational numbers
-rw-r--r-- | MANIFEST | 1 | ||||
-rw-r--r-- | calculate.py | 22 | ||||
-rw-r--r-- | eqnparser.py | 13 | ||||
-rw-r--r-- | mathlib.py | 8 | ||||
-rw-r--r-- | rational.py | 129 |
5 files changed, 163 insertions, 10 deletions
@@ -4,6 +4,7 @@ eqnparserhelp.py layout.py mathlib.py plotlib.py +rational.py svgimage.py toolbars.py po/Calculate.pot diff --git a/calculate.py b/calculate.py index 2e98d52..240e1c3 100644 --- a/calculate.py +++ b/calculate.py @@ -48,6 +48,7 @@ from eqnparser import EqnParser from svgimage import SVGImage from decimal import Decimal +from rational import Rational class Equation: def __init__(self, label=None, eqn=None, res=None, col=None, owner=None, str=None): @@ -328,14 +329,14 @@ class Calculate(activity.Activity): _logger.debug('process(): parsing %r, label: %r', s, label) res = self.parser.parse(s) - ansvar = self.parser.get_var('Ans') if type(res) == types.StringType and res.find('</svg>') > -1: res = SVGImage(data=res) # If parsing went ok, see if we have to replace the previous answer # to get a (more) exact result - elif res is not None and ansvar is not None and self.ans_inserted: + elif self.ans_inserted and res is not None: + ansvar = self.format_insert_ans() pos = s.find(ansvar) if len(ansvar) > 6 and pos != -1: s2 = s.replace(ansvar, 'LastEqn') @@ -347,8 +348,7 @@ class Calculate(activity.Activity): # Result ok if res is not None: self.add_equation(eqn) - self.parser.set_var('Ans', self.ml.format_number(eqn.result)) - self.parser.set_var('AnsExact', eqn.result) + self.parser.set_var('Ans', eqn.result) self.parser.set_var('LastEqn', eqn.equation) self.helper.send_message("add_eq", str(eqn)) self.showing_error = False @@ -403,7 +403,7 @@ class Calculate(activity.Activity): def refresh_vars(self): """Create list of TextViews with variables and display""" - reserved = ["Ans", "AnsExact", "LastEqn", "help"] + reserved = ["Ans", "LastEqn", "help"] list = [] for name, value in self.parser.get_vars(): if name in reserved: @@ -758,7 +758,7 @@ class Calculate(activity.Activity): if len(sel) is 2: pos = end elif pos == 0: - ans = self.parser.ml.format_number(self.parser.get_var('Ans')) + ans = self.format_insert_ans() str = ans + str self.ans_inserted = True self.text_entry.insert_text(str, pos) @@ -773,7 +773,7 @@ class Calculate(activity.Activity): or str in self.parser.get_post_operators()) and \ self.parser.get_var('Ans') is not None: # and \ # logic better? (str not in self.parser.get_pre_operators() or str == '+'): - ans = self.parser.ml.format_number(self.parser.get_var('Ans')) + ans = self.format_insert_ans() self.text_entry.set_text(ans + str) self.text_entry.set_position(len(ans) + len(str)) self.ans_inserted = True @@ -805,6 +805,14 @@ class Calculate(activity.Activity): self.add_equation(Equation(str=str(eq_str))) self.refresh_bar() + def format_insert_ans(self): + ans = self.parser.get_var('Ans') + if isinstance(ans, Rational): + ansstr = str(ans) + else: + ansstr = self.ml.format_number(ans) + return ansstr + def main(): win = gtk.Window(gtk.WINDOW_TOPLEVEL) t = Calculate(win) diff --git a/eqnparser.py b/eqnparser.py index 3264da2..b53e41d 100644 --- a/eqnparser.py +++ b/eqnparser.py @@ -26,6 +26,8 @@ from mathlib import MathLib from plotlib import PlotLib from eqnparserhelp import EqnParserHelp +from rational import Rational + from gettext import gettext as _ class Equation: @@ -210,8 +212,8 @@ class EqnParser: self.register_operator('*', self.OP_DIADIC, 1, lambda x: self.ml.mul(x[0], x[1])) self.register_operator(u'⨯', self.OP_DIADIC, 1, lambda x: self.ml.mul(x[0], x[1])) self.register_operator(u'×', self.OP_DIADIC, 1, lambda x: self.ml.mul(x[0], x[1])) - self.register_operator('/', self.OP_DIADIC, 1, lambda x: self.ml.div(x[0], x[1])) - self.register_operator(u'÷', self.OP_DIADIC, 1, lambda x: self.ml.div(x[0], x[1])) + self.register_operator('/', self.OP_DIADIC, 1, lambda x: self.div_operator(x[0], x[1])) + self.register_operator(u'÷', self.OP_DIADIC, 1, lambda x: self.div_operator(x[0], x[1])) self.register_operator('^', self.OP_DIADIC, 2, lambda x: self.ml.pow(x[0], x[1])) self.register_operator('**', self.OP_DIADIC, 2, lambda x: self.ml.pow(x[0], x[1])) @@ -639,3 +641,10 @@ class EqnParser: ret += op + " " return ret + def div_operator(self, a, b): + if isinstance(a, Rational) or isinstance(b, Rational): + return a / b + elif self.ml.is_int(a) and self.ml.is_int(b): + return Rational(a, b) + else: + return self.ml.div(a, b) @@ -20,6 +20,7 @@ import types import math from decimal import Decimal +from rational import Rational import random import logging @@ -103,7 +104,10 @@ class MathLib: def parse_number(self, s): try: d = Decimal(s) - return Decimal(s) + if self.is_int(d): + return int(d) + else: + return Decimal(s) except Exception, inst: return None @@ -125,6 +129,8 @@ class MathLib: n = self.d(n) elif type(n) is types.LongType: n = self.d(n) + elif isinstance(n, Rational): + n = self.d(float(n)) elif not isinstance(n, Decimal): return _('Error: unsupported type') (sign, digits, exp) = n.as_tuple() diff --git a/rational.py b/rational.py new file mode 100644 index 0000000..0a5571a --- /dev/null +++ b/rational.py @@ -0,0 +1,129 @@ +# rational.py, rational number class Reinier Heeres <reinier@heeres.eu> +# +# 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 St, Fifth Floor, Boston, MA 02110-1301 USA +# +# Change log: +# 2007-07-03: rwh, first version + +import types + +import logging +_logger = logging.getLogger('Rational') + +from gettext import gettext as _ + +class Rational: + + def __init__(self, n=None, d=None): + self.n = 0 + self.d = 0 + + if n is not None: + self.set(n, d) + + def set(self, n, d=None): + if d is not None: + self.n = long(n) + self.d = long(d) + elif type(n) is types.TupleType or type(n) is types.ListType: + self.n = long(rval[0]) + self.d = long(rval[1]) + elif type(n) == types.StringType: + return + + self._simplify() + + def __str__(self): + if self.d == 1 or self.d == 0: + return "%d" % (self.n) + else: + return "%d/%d" % (self.n, self.d) + + def __float__(self): + return float(self.n) / float(self.d) + + def gcd(self, a, b): + if b == 0: + return a + else: + return self.gcd(b, a % b) + + def _simplify(self): + if self.d == 0: + return + + if self.n == self.d: + self.n = long(1) + self.d = long(1) + else: + gcd = self.gcd(self.n, self.d) + self.n /= gcd + self.d /= gcd + + def __add__(self, rval): + if isinstance(rval, Rational): + ret = Rational(self.n * rval.d + self.d * rval.n, self.d * rval.d) + elif type(rval) is types.IntType or type(rval) is types.LongType: + ret = Rational(self.n + self.d * rval, self.d) + else: + ret = float(self) + rval + return ret + + def __radd__(self, lval): + return self.__add__(lval) + + def __sub__(self, rval): + if isinstance(rval, Rational): + ret = Rational(self.n * rval.d - self.d * rval.n, self.d * rval.d) + elif type(rval) is types.IntType or type(rval) is types.LongType: + ret = Rational(self.n - self.d * rval, self.d) + else: + ret = float(self) - rval + return ret + + def __rsub__(self, lval): + return self.__sub__(lval) + + def __mul__(self, rval): + if isinstance(rval, Rational): + ret = Rational(self.n * rval.n, self.d * rval.d) + elif type(rval) is types.IntType or type(rval) is types.LongType: + ret = Rational(self.n * rval, self.d) + else: + ret = float(self) * rval + return ret + + def __rmul__(self, lval): + return self.__mul__(lval) + + def __div__(self, rval): + if isinstance(rval, Rational): + ret = Rational(self.d * rval.d, self.n * rval.n) + elif type(rval) is types.IntType or type(rval) is types.LongType: + ret = Rational(self.n, self.d * rval) + else: + ret = float(self) / rval + return ret + + def __rdiv__(self, lval): + return self.__div__(lval) + + def __neg__(self): + self.n = -self.n + + def __abs__(self): + self.n = abs(self.n) + self.d = abs(self.d) + |