Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/functions.py
diff options
context:
space:
mode:
authorReinier Heeres <reinier@heeres.eu>2008-12-23 21:50:32 (GMT)
committer Reinier Heeres <reinier@heeres.eu>2008-12-23 21:50:32 (GMT)
commit6807696129436dbf071b606300ce6dda2adb1c50 (patch)
tree984328276f12f6d18f89ea5ea4e940a379c3993f /functions.py
parentf0b95df2389c5686979b489fa5f2084fd3738edf (diff)
Move to more flexible and faster parser based on python AST
Diffstat (limited to 'functions.py')
-rw-r--r--functions.py401
1 files changed, 401 insertions, 0 deletions
diff --git a/functions.py b/functions.py
new file mode 100644
index 0000000..b069581
--- /dev/null
+++ b/functions.py
@@ -0,0 +1,401 @@
+# functions.py, functions available in Calculate,
+# by 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
+
+# Any variable or function in this module that does not start with an
+# underscore ('_') will be available in Calculate through astparser.py.
+# Docstrings will automatically be added to the help index for that function.
+# However, instead of setting the docstring on a function in the simple way we
+# add it after the function definition so that they can more easily be
+# localized through gettext.
+
+import types
+import math
+import random
+from decimal import Decimal as _Decimal
+from rational import Rational as _Rational
+
+from gettext import gettext as _
+
+# List of functions to allow translating the function names.
+_FUNCTIONS = [
+ _('add'),
+ _('abs'),
+ _('acos'),
+ _('acosh'),
+ _('asin'),
+ _('asinh'),
+ _('atan'),
+ _('atanh'),
+ _('and'),
+ _('ceil'),
+ _('cos'),
+ _('cosh'),
+ _('div'),
+ _('gcd'),
+ _('exp'),
+ _('factorial'),
+ _('fac'),
+ _('factorize'),
+ _('floor'),
+ _('is_int'),
+ _('ln'),
+ _('log10'),
+ _('mul'),
+ _('or'),
+ _('rand_float'),
+ _('rand_int'),
+ _('round'),
+ _('sin'),
+ _('sinh'),
+ _('sinc'),
+ _('sqrt'),
+ _('sub'),
+ _('tan'),
+ _('tanh'),
+ _('xor'),
+ ]
+
+def _d(val):
+ '''Return a _Decimal object.'''
+
+ if isinstance(val, _Decimal):
+ return val
+ elif type(val) in (types.IntType, types.LongType):
+ return _Decimal(val)
+ elif type(val) == types.StringType:
+ d = _Decimal(val)
+ return d.normalize()
+ elif type(val) is types.FloatType or hasattr(val, '__float__'):
+ s = '%.10e' % float(val)
+ d = _Decimal(s)
+ return d.normalize()
+ else:
+ return None
+
+_angle_scaling = 1
+def _scale_angle(x):
+ return x * _angle_scaling
+
+def _inv_scale_angle(x):
+ return x / _angle_scaling
+
+def abs(x):
+ return math.fabs(x)
+abs.__doc__ = _(
+'abs(x), return absolute value of x, which means -x for x < 0')
+
+def acos(x):
+ return _inv_scale_angle(math.acos(x))
+acos.__doc__ = _(
+'acos(x), return the arc cosine of x. This is the angle for which the cosine \
+is x. Defined for -1 <= x < 1')
+
+def acosh(x):
+ return math.acosh(x)
+acosh.__doc__ = _(
+'acosh(x), return the arc hyperbolic cosine of x. This is the value y for \
+which the hyperbolic cosine equals x.')
+
+def And(x, y):
+ return x & y
+And.__doc__ = _(
+'And(x, y), logical and. Returns True if x and y are True, else returns False')
+
+def add(x, y):
+ if isinstance(x, _Decimal) or isinstance(y, _Decimal):
+ x = _d(x)
+ y = _d(y)
+ return x + y
+add.__doc__ = _('add(x, y), return x + y')
+
+def asin(x):
+ return _inv_scale_angle(math.asin(x))
+asin.__doc__ = _(
+'asin(x), return the arc sine of x. This is the angle for which the sine is ix. \
+Defined for -1 <= x <= 1')
+
+def asinh(x):
+ return math.asinh(x)
+asinh.__doc__ = _(
+'asinh(x), return the arc hyperbolic sine of x. This is the value y for \
+which the hyperbolic sine equals x.')
+
+def atan(x):
+ return _inv_scale_angle(math.atan(x))
+atan.__doc__ = _(
+'atan(x), return the arc tangent of x. This is the angle for which the tangent \
+is x. Defined for all x')
+
+def atanh(x):
+ return math.atanh(x)
+atanh.__doc__ = _(
+'atanh(x), return the arc hyperbolic tangent of x. This is the value y for \
+which the hyperbolic tangent equals x.')
+
+def ceil(x):
+ return math.ceil(float(x))
+ceil.__doc__ = _('ceil(x), return the smallest integer larger than x.')
+
+def cos(x):
+ return math.cos(_scale_angle(x))
+cos.__doc__ = _(
+'cos(x), return the cosine of x. This is the x-coordinate on the unit circle \
+at the angle x')
+
+def cosh(x):
+ return math.cosh(x)
+cosh.__doc__ = _(
+'cosh(x), return the hyperbolic cosine of x. Given by (exp(x) + exp(-x)) / 2')
+
+def div(x, y):
+ if y == 0 or y == 0.0:
+ raise ValueError(_('Can not divide by zero'))
+
+ if is_int(x) and float(abs(x)) < 1e12 and \
+ is_int(y) and float(abs(y)) < 1e12:
+ return _Rational(x, y)
+
+ if isinstance(x, _Decimal) or isinstance(y, _Decimal):
+ x = _d(x)
+ y = _d(y)
+
+ return x / y
+
+def _do_gcd(a, b):
+ if b == 0:
+ return a
+ else:
+ return self._do_gcd(b, a % b)
+
+def gcd(self, a, b):
+ TYPES = (types.IntType, types.LongType)
+ if type(a) not in TYPES or type(b) not in types:
+ raise ValueError(_('Invalid argument'))
+ return self._do_gcd(a, b)
+gcd.__doc__ = _(
+'gcd(a, b), determine the greatest common denominator of a and b. \
+For example, the biggest factor that is shared by the numbers 15 and 18 is 3.')
+
+def exp(x):
+ return math.exp(float(x))
+exp.__doc__ = _('exp(x), return the natural exponent of x. Given by e^x')
+
+def factorial(n):
+ if type(n) not in (types.IntType, types.LongType):
+ raise ValueError(_('Factorial only defined for integers'))
+
+ if n == 0:
+ return 1
+
+ n = long(n)
+ res = long(n)
+ while n > 2:
+ res *= n - 1
+ n -= 1
+
+ return res
+factorial.__doc__ = _(
+'factorial(n), return the factorial of n. \
+Given by n * (n - 1) * (n - 2) * ...')
+
+def fac(x):
+ return factorial(x)
+fac.__doc__ = _(
+'fac(x), return the factorial of x. Given by x * (x - 1) * (x - 2) * ...')
+
+def factorize(x):
+ if not is_int(x):
+ return 0
+
+ factors = []
+ num = x
+ i = 2
+ while i <= math.sqrt(num):
+ if num % i == 0:
+ factors.append(i)
+ num /= i
+ i = 2
+ elif i == 2:
+ i += 1
+ else:
+ i += 2
+ factors.append(num)
+
+ if len(factors) == 1:
+ return "1 * %d" % x
+ else:
+ ret = "%d" % factors[0]
+ for fac in factors[1:]:
+ ret += " * %d" % fac
+ return ret
+factorize.__doc__ = (
+'factorize(x), determine the prime factors that together form x. \
+For examples: 15 = 3 * 5.')
+
+def floor(x):
+ return math.floor(float(x))
+floor.__doc__ = _('floor(x), return the largest integer smaller than x.')
+
+def is_int(n):
+ if type(n) in (types.IntType, types.LongType):
+ return True
+
+ if not isinstance(n, _Decimal):
+ n = _d(n)
+ if n is None:
+ return False
+
+
+ (sign, d, e) = n.normalize().as_tuple()
+ return e >= 0
+is_int.__doc__ = ('is_int(n), determine whether n is an integer.')
+
+def ln(x):
+ if float(x) > 0:
+ return math.log(float(x))
+ else:
+ raise ValueError(_('Logarithm(x) only defined for x > 0'))
+ln.__doc__ = _(
+'ln(x), return the natural logarithm of x. This is the value for which the \
+exponent exp() equals x. Defined for x >= 0.')
+
+def log10(x):
+ if float(x) > 0:
+ return math.log(float(x))
+ else:
+ raise ValueError(_('Logarithm(x) only defined for x > 0'))
+log10.__doc__ = _(
+'log10(x), return the base 10 logarithm of x. This is the value y for which \
+10^y equals x. Defined for x >= 0.')
+
+def mod(x, y):
+ if self.is_int(y):
+ return x % y
+ else:
+ raise ValueError(_('Can only calculate x modulo <integer>'))
+
+def mul(x, y):
+ if isinstance(x, _Decimal) or isinstance(y, _Decimal):
+ x = _d(x)
+ y = _d(y)
+ return x * y
+mul.__doc__ = _('mul(x, y), return x * y')
+
+def negate(x):
+ return -x
+negate.__doc__ = _('negate(x), return -x')
+
+def Or(x, y):
+ return x | y
+Or.__doc__ = _(
+'Or(x, y), logical or. Returns True if x or y is True, else returns False')
+
+def pow(x, y):
+ if is_int(y):
+ if is_int(x):
+ return long(x) ** int(y)
+ elif hasattr(x, '__pow__'):
+ return x ** y
+ else:
+ return float(x) ** int(y)
+ else:
+ if isinstance(x, _Decimal) or isinstance(y, _Decimal):
+ x = _d(x)
+ y = _d(y)
+ return _d(math.pow(float(x), float(y)))
+pow.__doc__ = _('pow(x, y), return x to the power y (x**y)')
+
+def rand_float():
+ return random.random()
+rand_float.__doc__ = _(
+'rand_float(), return a random floating point number between 0.0 and 1.0')
+
+def rand_int(maxval=65535):
+ return random.randint(0, maxval)
+rand_int.__doc__ = _(
+'rand_int([<maxval>]), return a random integer between 0 and <maxval>. \
+<maxval> is an optional argument and is set to 65535 by default.')
+
+def round(x):
+ return math.round(float(x))
+round.__doc__ = _('round(x), return the integer nearest to x.')
+
+def shift_left(x, y):
+ if is_int(x) and is_int(y):
+ return d(int(x) << int(y))
+ else:
+ raise ValueError(_('Bitwise operations only apply to integers'))
+shift_left.__doc__ = _(
+'shift_left(x, y), shift x by y bits to the left (multiply by 2 per bit)')
+
+def shift_right(self, x, y):
+ if is_int(x) and is_int(y):
+ return d(int(x) >> int(y))
+ else:
+ raise ValueError(_('Bitwise operations only apply to integers'))
+shift_right.__doc__ = _(
+'shift_right(x, y), shift x by y bits to the right (divide by 2 per bit)')
+
+def sin(x):
+ return math.sin(_scale_angle(x))
+sin.__doc__ = _(
+'sin(x), return the sine of x. This is the y-coordinate on the unit circle at \
+the angle x')
+
+def sinh(x):
+ return math.sinh(x)
+sinh.__doc__ = _(
+'sinh(x), return the hyperbolic sine of x. Given by (exp(x) - exp(-x)) / 2')
+
+def sinc(x):
+ if float(x) == 0.0:
+ return 1
+ return sin(x) / x
+sinc.__doc__ = _(
+'sinc(x), return the sinc of x. This is given by sin(x) / x.')
+
+def sqrt(x):
+ return math.sqrt(float(x))
+sqrt.__doc__ = _(
+'sqrt(x), return the square root of x. This is the value for which the square \
+equals x. Defined for x >= 0.')
+
+def sub(x, y):
+ if isinstance(x, _Decimal) or isinstance(y, _Decimal):
+ x = _d(x)
+ y = _d(y)
+ return x - y
+add.__doc__ = _('sub(x, y), return x - y')
+
+def tan(x):
+ return math.tan(_scale_angle(x))
+tan.__doc__ = _(
+'tan(x), return the tangent of x. This is the slope of the line from the origin \
+of the unit circle to the point on the unit circle defined by the angle x. Given \
+by sin(x) / cos(x)')
+
+def tanh(x):
+ return math.tanh(x)
+tanh.__doc__ = _(
+'tanh(x), return the hyperbolic tangent of x. Given by sinh(x) / cosh(x)')
+
+def xor(x, y):
+ return x ^ y
+xor.__doc__ = _(
+'xor(x, y), logical xor. Returns True if either x is True (and y is False) \
+or y is True (and x is False), else returns False')
+