from __future__ import print_function, division
from sympy.core.singleton import S
from sympy.core.function import Function
from sympy.core import Add
from sympy.core.evalf import get_integer_part, PrecisionExhausted
from sympy.core.numbers import Integer
from sympy.core.relational import Gt, Lt, Ge, Le
from sympy.core.symbol import Symbol
###############################################################################
######################### FLOOR and CEILING FUNCTIONS #########################
###############################################################################
[docs]class RoundFunction(Function):
"""The base class for rounding functions."""
@classmethod
def eval(cls, arg):
from sympy import im
if arg.is_integer:
return arg
if arg.is_imaginary or (S.ImaginaryUnit*arg).is_real:
i = im(arg)
if not i.has(S.ImaginaryUnit):
return cls(i)*S.ImaginaryUnit
return cls(arg, evaluate=False)
v = cls._eval_number(arg)
if v is not None:
return v
# Integral, numerical, symbolic part
ipart = npart = spart = S.Zero
# Extract integral (or complex integral) terms
terms = Add.make_args(arg)
for t in terms:
if t.is_integer or (t.is_imaginary and im(t).is_integer):
ipart += t
elif t.has(Symbol):
spart += t
else:
npart += t
if not (npart or spart):
return ipart
# Evaluate npart numerically if independent of spart
if npart and (
not spart or
npart.is_real and (spart.is_imaginary or (S.ImaginaryUnit*spart).is_real) or
npart.is_imaginary and spart.is_real):
try:
r, i = get_integer_part(
npart, cls._dir, {}, return_ints=True)
ipart += Integer(r) + Integer(i)*S.ImaginaryUnit
npart = S.Zero
except (PrecisionExhausted, NotImplementedError):
pass
spart += npart
if not spart:
return ipart
elif spart.is_imaginary or (S.ImaginaryUnit*spart).is_real:
return ipart + cls(im(spart), evaluate=False)*S.ImaginaryUnit
else:
return ipart + cls(spart, evaluate=False)
def _eval_is_finite(self):
return self.args[0].is_finite
def _eval_is_real(self):
return self.args[0].is_real
def _eval_is_integer(self):
return self.args[0].is_real
[docs]class floor(RoundFunction):
"""
Floor is a univariate function which returns the largest integer
value not greater than its argument. However this implementation
generalizes floor to complex numbers.
Examples
========
>>> from sympy import floor, E, I, Float, Rational
>>> floor(17)
17
>>> floor(Rational(23, 10))
2
>>> floor(2*E)
5
>>> floor(-Float(0.567))
-1
>>> floor(-I/2)
-I
See Also
========
sympy.functions.elementary.integers.ceiling
References
==========
.. [1] "Concrete mathematics" by Graham, pp. 87
.. [2] http://mathworld.wolfram.com/FloorFunction.html
"""
_dir = -1
@classmethod
def _eval_number(cls, arg):
if arg.is_Number:
if arg.is_Rational:
return Integer(arg.p // arg.q)
elif arg.is_Float:
return Integer(int(arg.floor()))
else:
return arg
if arg.is_NumberSymbol:
return arg.approximation_interval(Integer)[0]
def _eval_nseries(self, x, n, logx):
r = self.subs(x, 0)
args = self.args[0]
args0 = args.subs(x, 0)
if args0 == r:
direction = (args - args0).leadterm(x)[0]
if direction.is_positive:
return r
else:
return r - 1
else:
return r
def __le__(self, other):
if self.args[0] == other and other.is_real:
return S.true
return Le(self, other, evaluate=False)
def __gt__(self, other):
if self.args[0] == other and other.is_real:
return S.false
return Gt(self, other, evaluate=False)
[docs]class ceiling(RoundFunction):
"""
Ceiling is a univariate function which returns the smallest integer
value not less than its argument. Ceiling function is generalized
in this implementation to complex numbers.
Examples
========
>>> from sympy import ceiling, E, I, Float, Rational
>>> ceiling(17)
17
>>> ceiling(Rational(23, 10))
3
>>> ceiling(2*E)
6
>>> ceiling(-Float(0.567))
0
>>> ceiling(I/2)
I
See Also
========
sympy.functions.elementary.integers.floor
References
==========
.. [1] "Concrete mathematics" by Graham, pp. 87
.. [2] http://mathworld.wolfram.com/CeilingFunction.html
"""
_dir = 1
@classmethod
def _eval_number(cls, arg):
if arg.is_Number:
if arg.is_Rational:
return -Integer(-arg.p // arg.q)
elif arg.is_Float:
return Integer(int(arg.ceiling()))
else:
return arg
if arg.is_NumberSymbol:
return arg.approximation_interval(Integer)[1]
def _eval_nseries(self, x, n, logx):
r = self.subs(x, 0)
args = self.args[0]
args0 = args.subs(x, 0)
if args0 == r:
direction = (args - args0).leadterm(x)[0]
if direction.is_positive:
return r + 1
else:
return r
else:
return r
def __lt__(self, other):
if self.args[0] == other and other.is_real:
return S.false
return Lt(self, other, evaluate=False)
def __ge__(self, other):
if self.args[0] == other and other.is_real:
return S.true
return Ge(self, other, evaluate=False)
[docs]class frac(Function):
r"""Represents the fractional part of x
For real numbers it is defined [1]_ as
.. math::
x - \lfloor{x}\rfloor
Examples
========
>>> from sympy import Symbol, frac, Rational, floor, ceiling, I
>>> frac(Rational(4, 3))
1/3
>>> frac(-Rational(4, 3))
2/3
returns zero for integer arguments
>>> n = Symbol('n', integer=True)
>>> frac(n)
0
rewrite as floor
>>> x = Symbol('x')
>>> frac(x).rewrite(floor)
x - floor(x)
for complex arguments
>>> r = Symbol('r', real=True)
>>> t = Symbol('t', real=True)
>>> frac(t + I*r)
I*frac(r) + frac(t)
See Also
========
sympy.functions.elementary.integers.floor
sympy.functions.elementary.integers.ceiling
References
===========
.. [1] http://en.wikipedia.org/wiki/Fractional_part
.. [2] http://mathworld.wolfram.com/FractionalPart.html
"""
@classmethod
def eval(cls, arg):
from sympy import AccumBounds, im
def _eval(arg):
if arg is S.Infinity or arg is S.NegativeInfinity:
return AccumBounds(0, 1)
if arg.is_integer:
return S.Zero
if arg.is_number:
if arg is S.NaN:
return S.NaN
elif arg is S.ComplexInfinity:
return None
else:
return arg - floor(arg)
return cls(arg, evaluate=False)
terms = Add.make_args(arg)
real, imag = S.Zero, S.Zero
for t in terms:
# Two checks are needed for complex arguments
# see issue-7649 for details
if t.is_imaginary or (S.ImaginaryUnit*t).is_real:
i = im(t)
if not i.has(S.ImaginaryUnit):
imag += i
else:
real += t
else:
real += t
real = _eval(real)
imag = _eval(imag)
return real + S.ImaginaryUnit*imag
def _eval_rewrite_as_floor(self, arg):
return arg - floor(arg)