| 1 | """num.py - math functions"""
 | 
| 2 | from __future__ import print_function
 | 
| 3 | 
 | 
| 4 | from _devbuild.gen.value_asdl import value
 | 
| 5 | from mycpp import mops
 | 
| 6 | 
 | 
| 7 | 
 | 
| 8 | def ToBig(i):
 | 
| 9 |     # type: (int) -> value.Int
 | 
| 10 |     return value.Int(mops.IntWiden(i))
 | 
| 11 | 
 | 
| 12 | 
 | 
| 13 | def Exponent(x, y):
 | 
| 14 |     # type: (mops.BigInt, mops.BigInt) -> mops.BigInt
 | 
| 15 | 
 | 
| 16 |     # TODO: can we avoid this?
 | 
| 17 |     y_int = mops.BigTruncate(y)
 | 
| 18 | 
 | 
| 19 |     assert y_int >= 0, 'checked by caller'
 | 
| 20 | 
 | 
| 21 |     result = mops.BigInt(1)
 | 
| 22 |     for i in xrange(y_int):
 | 
| 23 |         result = mops.Mul(result, x)
 | 
| 24 |     return result
 | 
| 25 | 
 | 
| 26 | 
 | 
| 27 | def Exponent2(x, y):
 | 
| 28 |     # type: (int, int) -> int
 | 
| 29 |     return mops.BigTruncate(Exponent(mops.IntWiden(x), mops.IntWiden(y)))
 | 
| 30 | 
 | 
| 31 | 
 | 
| 32 | def IntDivide(x, y):
 | 
| 33 |     # type: (mops.BigInt, mops.BigInt) -> mops.BigInt
 | 
| 34 |     """
 | 
| 35 |     Implementation that only uses the host language (Python or C++) to divide
 | 
| 36 |     non-negative numbers.  Python rounds toward negative infinity, while C++
 | 
| 37 |     rounds toward zero.
 | 
| 38 | 
 | 
| 39 |     Oils rounds toward zero.
 | 
| 40 |     """
 | 
| 41 |     assert y.i != 0, 'checked by caller'
 | 
| 42 | 
 | 
| 43 |     ZERO = mops.BigInt(0)
 | 
| 44 |     sign = 1
 | 
| 45 | 
 | 
| 46 |     if mops.Greater(ZERO, x):
 | 
| 47 |         ax = mops.Negate(x)
 | 
| 48 |         sign = -1
 | 
| 49 |     else:
 | 
| 50 |         ax = x
 | 
| 51 | 
 | 
| 52 |     if mops.Greater(ZERO, y):
 | 
| 53 |         ay = mops.Negate(y)
 | 
| 54 |         sign = -sign
 | 
| 55 |     else:
 | 
| 56 |         ay = y
 | 
| 57 | 
 | 
| 58 |     return mops.Mul(mops.IntWiden(sign), mops.Div(ax, ay))
 | 
| 59 | 
 | 
| 60 | 
 | 
| 61 | def IntDivide2(x, y):
 | 
| 62 |     # type: (int, int) -> int
 | 
| 63 |     return mops.BigTruncate(IntDivide(mops.IntWiden(x), mops.IntWiden(y)))
 | 
| 64 | 
 | 
| 65 | 
 | 
| 66 | def IntRemainder(x, y):
 | 
| 67 |     # type: (mops.BigInt, mops.BigInt) -> mops.BigInt
 | 
| 68 |     """
 | 
| 69 |     Implementation that only uses the host language (Python or C++) to divide
 | 
| 70 |     non-negative numbers.
 | 
| 71 | 
 | 
| 72 |     Takes the sign of the first argument x.
 | 
| 73 | 
 | 
| 74 |     Python % is modulus, while C % is remainder.  Both OSH and YSH % is
 | 
| 75 |     remainder, like C.
 | 
| 76 |     """
 | 
| 77 |     assert y.i != 0, 'checked by caller'
 | 
| 78 | 
 | 
| 79 |     ZERO = mops.BigInt(0)
 | 
| 80 | 
 | 
| 81 |     if mops.Greater(ZERO, x):
 | 
| 82 |         ax = mops.Negate(x)
 | 
| 83 |         sign = -1
 | 
| 84 |     else:
 | 
| 85 |         ax = x
 | 
| 86 |         sign = 1
 | 
| 87 | 
 | 
| 88 |     if mops.Greater(ZERO, y):
 | 
| 89 |         ay = mops.Negate(y)
 | 
| 90 |     else:
 | 
| 91 |         ay = y
 | 
| 92 | 
 | 
| 93 |     # Only use host language % on non-negative numbers.  Apply sign afteward.
 | 
| 94 |     return mops.Mul(mops.IntWiden(sign), mops.Rem(ax, ay))
 | 
| 95 | 
 | 
| 96 | 
 | 
| 97 | def IntRemainder2(x, y):
 | 
| 98 |     # type: (int, int) -> int
 | 
| 99 |     return mops.BigTruncate(IntRemainder(mops.IntWiden(x), mops.IntWiden(y)))
 |