Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorReinier Heeres <reinier@heeres.eu>2007-11-18 19:34:59 (GMT)
committer Reinier Heeres <reinier@heeres.eu>2007-11-18 19:34:59 (GMT)
commitf8a8343c92f8ab54614660c235c6e6c18e5464db (patch)
treec61d024118ce3dc7ca3da8b9e210a65601b9f6e6
parent29e05573dd8f69fe474433dac8873fab7aeda6f0 (diff)
Included support for rational numbers
-rw-r--r--MANIFEST1
-rw-r--r--calculate.py22
-rw-r--r--eqnparser.py13
-rw-r--r--mathlib.py8
-rw-r--r--rational.py129
5 files changed, 163 insertions, 10 deletions
diff --git a/MANIFEST b/MANIFEST
index 1b968bc..1de501d 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -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)
diff --git a/mathlib.py b/mathlib.py
index 6693bc6..ff17de5 100644
--- a/mathlib.py
+++ b/mathlib.py
@@ -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)
+