OILS / core / num.py View on Github | oilshell.org

99 lines, 47 significant
1"""num.py - math functions"""
2from __future__ import print_function
3
4from _devbuild.gen.value_asdl import value
5from mycpp import mops
6
7
8def ToBig(i):
9 # type: (int) -> value.Int
10 return value.Int(mops.IntWiden(i))
11
12
13def 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
27def Exponent2(x, y):
28 # type: (int, int) -> int
29 return mops.BigTruncate(Exponent(mops.IntWiden(x), mops.IntWiden(y)))
30
31
32def 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
61def IntDivide2(x, y):
62 # type: (int, int) -> int
63 return mops.BigTruncate(IntDivide(mops.IntWiden(x), mops.IntWiden(y)))
64
65
66def 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
97def IntRemainder2(x, y):
98 # type: (int, int) -> int
99 return mops.BigTruncate(IntRemainder(mops.IntWiden(x), mops.IntWiden(y)))