683 lines
20 KiB
Python
683 lines
20 KiB
Python
"""
|
|
Java math standard library APIs implemented in Python.
|
|
java.math package - BigInteger, BigDecimal, MathContext, RoundingMode.
|
|
"""
|
|
|
|
from .._core import Stub
|
|
from .lang import Comparable
|
|
from decimal import (
|
|
Decimal as _Decimal,
|
|
ROUND_DOWN as _DEC_ROUND_DOWN,
|
|
ROUND_HALF_UP as _DEC_ROUND_HALF_UP,
|
|
ROUND_HALF_EVEN as _DEC_ROUND_HALF_EVEN,
|
|
ROUND_UP as _DEC_ROUND_UP,
|
|
ROUND_CEILING as _DEC_ROUND_CEILING,
|
|
ROUND_FLOOR as _DEC_ROUND_FLOOR,
|
|
ROUND_HALF_DOWN as _DEC_ROUND_HALF_DOWN,
|
|
localcontext as _local_context,
|
|
getcontext as _get_context,
|
|
)
|
|
import random as _random
|
|
import math as _py_math
|
|
import sys as _sys
|
|
|
|
__all__ = [
|
|
"BigInteger", "BigDecimal", "MathContext", "RoundingMode",
|
|
]
|
|
|
|
|
|
# ============================================================
|
|
# RoundingMode
|
|
# ============================================================
|
|
|
|
class RoundingMode(Stub):
|
|
UP = 0
|
|
DOWN = 1
|
|
CEILING = 2
|
|
FLOOR = 3
|
|
HALF_UP = 4
|
|
HALF_DOWN = 5
|
|
HALF_EVEN = 6
|
|
UNNECESSARY = 7
|
|
|
|
_names = {
|
|
0: "UP", 1: "DOWN", 2: "CEILING", 3: "FLOOR",
|
|
4: "HALF_UP", 5: "HALF_DOWN", 6: "HALF_EVEN", 7: "UNNECESSARY",
|
|
}
|
|
|
|
_py_map = {
|
|
0: _DEC_ROUND_UP,
|
|
1: _DEC_ROUND_DOWN,
|
|
2: _DEC_ROUND_CEILING,
|
|
3: _DEC_ROUND_FLOOR,
|
|
4: _DEC_ROUND_HALF_UP,
|
|
5: _DEC_ROUND_HALF_DOWN,
|
|
6: _DEC_ROUND_HALF_EVEN,
|
|
7: _DEC_ROUND_HALF_EVEN, # closest approximation
|
|
}
|
|
|
|
def __init__(self, value):
|
|
super().__init__()
|
|
self._value = value
|
|
|
|
def toString(self):
|
|
return self._names.get(self._value, "UNKNOWN")
|
|
|
|
|
|
# ============================================================
|
|
# MathContext
|
|
# ============================================================
|
|
|
|
class MathContext(Stub):
|
|
UNLIMITED = None
|
|
DECIMAL32 = None
|
|
DECIMAL64 = None
|
|
DECIMAL128 = None
|
|
|
|
def __init__(self, *args):
|
|
super().__init__()
|
|
if len(args) == 1:
|
|
if isinstance(args[0], str):
|
|
s = args[0].strip().lower()
|
|
if s == "precision=7 roundingmode=half_even":
|
|
self._precision = 7
|
|
self._rounding_mode = RoundingMode.HALF_EVEN
|
|
elif s == "precision=16 roundingmode=half_even":
|
|
self._precision = 16
|
|
self._rounding_mode = RoundingMode.HALF_EVEN
|
|
elif s == "precision=34 roundingmode=half_even":
|
|
self._precision = 34
|
|
self._rounding_mode = RoundingMode.HALF_EVEN
|
|
else:
|
|
self._precision = 0
|
|
self._rounding_mode = RoundingMode.HALF_UP
|
|
else:
|
|
self._precision = int(args[0])
|
|
self._rounding_mode = RoundingMode.HALF_UP
|
|
elif len(args) == 2:
|
|
self._precision = int(args[0])
|
|
self._rounding_mode = args[1]
|
|
|
|
def getPrecision(self):
|
|
return self._precision
|
|
|
|
def getRoundingMode(self):
|
|
return self._rounding_mode
|
|
|
|
def equals(self, other):
|
|
if isinstance(other, MathContext):
|
|
return (self._precision == other._precision and
|
|
self._rounding_mode == other._rounding_mode)
|
|
return False
|
|
|
|
def hashCode(self):
|
|
return hash((self._precision, self._rounding_mode)) & 0x7FFFFFFF
|
|
|
|
def toString(self):
|
|
return f"precision={self._precision} roundingMode={self._rounding_mode.toString()}"
|
|
|
|
|
|
MathContext.UNLIMITED = MathContext(0)
|
|
MathContext.DECIMAL32 = MathContext(7, RoundingMode.HALF_EVEN)
|
|
MathContext.DECIMAL64 = MathContext(16, RoundingMode.HALF_EVEN)
|
|
MathContext.DECIMAL128 = MathContext(34, RoundingMode.HALF_EVEN)
|
|
|
|
|
|
# ============================================================
|
|
# BigInteger
|
|
# ============================================================
|
|
|
|
class BigInteger(Comparable):
|
|
ZERO = None
|
|
ONE = None
|
|
TEN = None
|
|
|
|
def __init__(self, *args):
|
|
super().__init__()
|
|
if len(args) == 0:
|
|
self._value = 0
|
|
elif len(args) == 1:
|
|
if isinstance(args[0], str):
|
|
self._value = int(str(args[0]))
|
|
elif isinstance(args[0], bytes):
|
|
self._value = int.from_bytes(args[0], byteorder="big", signed=True)
|
|
elif isinstance(args[0], bytearray):
|
|
self._value = int.from_bytes(bytes(args[0]), byteorder="big", signed=True)
|
|
elif isinstance(args[0], int):
|
|
self._value = args[0]
|
|
elif isinstance(args[0], BigInteger):
|
|
self._value = args[0]._value
|
|
else:
|
|
self._value = int(args[0])
|
|
elif len(args) == 2:
|
|
if isinstance(args[1], _random.Random):
|
|
bit_length, rng = args
|
|
self._value = rng.getrandbits(bit_length)
|
|
elif isinstance(args[1], int):
|
|
val_str, radix = args
|
|
self._value = int(str(val_str), radix)
|
|
else:
|
|
self._value = int.from_bytes(bytes(args[0]), byteorder="big", signed=True)
|
|
else:
|
|
self._value = 0
|
|
|
|
@staticmethod
|
|
def valueOf(val):
|
|
if isinstance(val, int):
|
|
if val == 0:
|
|
return BigInteger.ZERO
|
|
if val == 1:
|
|
return BigInteger.ONE
|
|
if val == 10:
|
|
return BigInteger.TEN
|
|
return BigInteger(val)
|
|
|
|
def add(self, other):
|
|
if isinstance(other, BigInteger):
|
|
return BigInteger(self._value + other._value)
|
|
return BigInteger(self._value + int(other))
|
|
|
|
def subtract(self, other):
|
|
if isinstance(other, BigInteger):
|
|
return BigInteger(self._value - other._value)
|
|
return BigInteger(self._value - int(other))
|
|
|
|
def multiply(self, other):
|
|
if isinstance(other, BigInteger):
|
|
return BigInteger(self._value * other._value)
|
|
return BigInteger(self._value * int(other))
|
|
|
|
def divide(self, other):
|
|
if isinstance(other, BigInteger):
|
|
return BigInteger(self._value // other._value)
|
|
return BigInteger(self._value // int(other))
|
|
|
|
def pow(self, exponent):
|
|
return BigInteger(self._value ** exponent)
|
|
|
|
def gcd(self, other):
|
|
return BigInteger(_py_math.gcd(self._value, other._value if isinstance(other, BigInteger) else int(other)))
|
|
|
|
def abs(self):
|
|
return BigInteger(abs(self._value))
|
|
|
|
def negate(self):
|
|
return BigInteger(-self._value)
|
|
|
|
def signum(self):
|
|
if self._value > 0:
|
|
return 1
|
|
if self._value < 0:
|
|
return -1
|
|
return 0
|
|
|
|
def mod(self, m):
|
|
if isinstance(m, BigInteger):
|
|
return BigInteger(self._value % m._value)
|
|
return BigInteger(self._value % int(m))
|
|
|
|
def remainder(self, other):
|
|
if isinstance(other, BigInteger):
|
|
return BigInteger(self._value % other._value)
|
|
return BigInteger(self._value % int(other))
|
|
|
|
def and_(self, other):
|
|
return BigInteger(self._value & (other._value if isinstance(other, BigInteger) else int(other)))
|
|
|
|
def or_(self, other):
|
|
return BigInteger(self._value | (other._value if isinstance(other, BigInteger) else int(other)))
|
|
|
|
def xor(self, other):
|
|
return BigInteger(self._value ^ (other._value if isinstance(other, BigInteger) else int(other)))
|
|
|
|
def not_(self):
|
|
return BigInteger(~self._value)
|
|
|
|
def andNot(self, other):
|
|
return BigInteger(self._value & ~(other._value if isinstance(other, BigInteger) else int(other)))
|
|
|
|
def shiftLeft(self, n):
|
|
return BigInteger(self._value << n)
|
|
|
|
def shiftRight(self, n):
|
|
return BigInteger(self._value >> n)
|
|
|
|
def getLowestSetBit(self):
|
|
if self._value == 0:
|
|
return -1
|
|
return (self._value & -self._value).bit_length() - 1
|
|
|
|
def bitLength(self):
|
|
if self._value == 0:
|
|
return 0
|
|
return self._value.bit_length()
|
|
|
|
def bitCount(self):
|
|
return bin(self._value & ((1 << self.bitLength()) - 1) if self._value >= 0 else self._value).count("1")
|
|
|
|
def isProbablePrime(self, certainty):
|
|
if abs(self._value) < 2:
|
|
return False
|
|
if abs(self._value) == 2 or abs(self._value) == 3:
|
|
return True
|
|
if self._value % 2 == 0:
|
|
return False
|
|
d = self._value - 1
|
|
s = 0
|
|
while d % 2 == 0:
|
|
d //= 2
|
|
s += 1
|
|
for _ in range(min(certainty, 20)):
|
|
a = _random.randrange(2, min(self._value - 1, 1000000))
|
|
x = pow(a, d, self._value)
|
|
if x == 1 or x == self._value - 1:
|
|
continue
|
|
for _ in range(s - 1):
|
|
x = pow(x, 2, self._value)
|
|
if x == self._value - 1:
|
|
break
|
|
else:
|
|
return False
|
|
return True
|
|
|
|
def nextProbablePrime(self):
|
|
v = self._value + 1
|
|
if v < 3:
|
|
return BigInteger(2) if v <= 2 else BigInteger(3)
|
|
while True:
|
|
if v % 2 == 0:
|
|
v += 1
|
|
for i in range(3, int(_py_math.sqrt(v)) + 1, 2):
|
|
if v % i == 0:
|
|
break
|
|
else:
|
|
return BigInteger(v)
|
|
v += 2
|
|
|
|
def compareTo(self, other):
|
|
if isinstance(other, BigInteger):
|
|
return (self._value > other._value) - (self._value < other._value)
|
|
return -1
|
|
|
|
def equals(self, other):
|
|
if isinstance(other, BigInteger):
|
|
return self._value == other._value
|
|
return False
|
|
|
|
def toByteArray(self):
|
|
if self._value == 0:
|
|
return b"\x00"
|
|
byte_length = (self._value.bit_length() + 8) // 8
|
|
return self._value.to_bytes(byte_length, byteorder="big", signed=True)
|
|
|
|
def toString(self, radix=10):
|
|
if radix == 10:
|
|
return str(self._value)
|
|
if radix == 16:
|
|
return hex(self._value)[2:]
|
|
if radix == 8:
|
|
return oct(self._value)[2:]
|
|
if radix == 2:
|
|
return bin(self._value)[2:]
|
|
return str(self._value)
|
|
|
|
def intValue(self):
|
|
return self._value & 0xFFFFFFFF
|
|
|
|
def longValue(self):
|
|
return self._value
|
|
|
|
def floatValue(self):
|
|
return float(self._value)
|
|
|
|
def doubleValue(self):
|
|
return float(self._value)
|
|
|
|
def min(self, other):
|
|
return BigInteger(min(self._value, other._value if isinstance(other, BigInteger) else int(other)))
|
|
|
|
def max(self, other):
|
|
return BigInteger(max(self._value, other._value if isinstance(other, BigInteger) else int(other)))
|
|
|
|
def modPow(self, exponent, m):
|
|
if isinstance(exponent, BigInteger):
|
|
exp_val = exponent._value
|
|
else:
|
|
exp_val = int(exponent)
|
|
mod_val = m._value if isinstance(m, BigInteger) else int(m)
|
|
return BigInteger(pow(self._value, exp_val, mod_val))
|
|
|
|
def modInverse(self, m):
|
|
mod_val = m._value if isinstance(m, BigInteger) else int(m)
|
|
return BigInteger(pow(self._value, -1, mod_val))
|
|
|
|
def divideAndRemainder(self, other):
|
|
if isinstance(other, BigInteger):
|
|
divisor = other._value
|
|
else:
|
|
divisor = int(other)
|
|
q = self._value // divisor
|
|
r = self._value % divisor
|
|
return [BigInteger(q), BigInteger(r)]
|
|
|
|
def __int__(self):
|
|
return self._value
|
|
|
|
def __str__(self):
|
|
return str(self._value)
|
|
|
|
def __neg__(self):
|
|
return self.negate()
|
|
|
|
def __abs__(self):
|
|
return self.abs()
|
|
|
|
def __add__(self, other):
|
|
return self.add(other)
|
|
|
|
def __sub__(self, other):
|
|
return self.subtract(other)
|
|
|
|
def __mul__(self, other):
|
|
return self.multiply(other)
|
|
|
|
def __truediv__(self, other):
|
|
return self.divide(other)
|
|
|
|
def __floordiv__(self, other):
|
|
return self.divide(other)
|
|
|
|
def __mod__(self, other):
|
|
return self.mod(other)
|
|
|
|
def __pow__(self, other):
|
|
return self.pow(other)
|
|
|
|
def __and__(self, other):
|
|
return self.and_(other)
|
|
|
|
def __or__(self, other):
|
|
return self.or_(other)
|
|
|
|
def __xor__(self, other):
|
|
return self.xor(other)
|
|
|
|
def __invert__(self):
|
|
return self.not_()
|
|
|
|
def __lshift__(self, n):
|
|
return self.shiftLeft(n)
|
|
|
|
def __rshift__(self, n):
|
|
return self.shiftRight(n)
|
|
|
|
|
|
BigInteger.ZERO = BigInteger(0)
|
|
BigInteger.ONE = BigInteger(1)
|
|
BigInteger.TEN = BigInteger(10)
|
|
|
|
|
|
# ============================================================
|
|
# BigDecimal
|
|
# ============================================================
|
|
|
|
class BigDecimal(Comparable):
|
|
ZERO = None
|
|
ONE = None
|
|
TEN = None
|
|
|
|
ROUND_UP = 0
|
|
ROUND_DOWN = 1
|
|
ROUND_CEILING = 2
|
|
ROUND_FLOOR = 3
|
|
ROUND_HALF_UP = 4
|
|
ROUND_HALF_DOWN = 5
|
|
ROUND_HALF_EVEN = 6
|
|
ROUND_UNNECESSARY = 7
|
|
|
|
_round_map = {
|
|
0: _DEC_ROUND_UP,
|
|
1: _DEC_ROUND_DOWN,
|
|
2: _DEC_ROUND_CEILING,
|
|
3: _DEC_ROUND_FLOOR,
|
|
4: _DEC_ROUND_HALF_UP,
|
|
5: _DEC_ROUND_HALF_DOWN,
|
|
6: _DEC_ROUND_HALF_EVEN,
|
|
7: _DEC_ROUND_HALF_EVEN,
|
|
}
|
|
|
|
def __init__(self, *args):
|
|
super().__init__()
|
|
if len(args) == 1:
|
|
val = args[0]
|
|
if isinstance(val, str):
|
|
self._dec = _Decimal(str(val))
|
|
elif isinstance(val, float):
|
|
self._dec = _Decimal(repr(val))
|
|
elif isinstance(val, int):
|
|
self._dec = _Decimal(val)
|
|
elif isinstance(val, BigInteger):
|
|
self._dec = _Decimal(val._value)
|
|
elif isinstance(val, BigDecimal):
|
|
self._dec = _Decimal(val._dec)
|
|
elif isinstance(val, _Decimal):
|
|
self._dec = val
|
|
else:
|
|
self._dec = _Decimal(str(val))
|
|
elif len(args) == 2:
|
|
val, mc = args
|
|
if isinstance(val, str):
|
|
self._dec = _Decimal(str(val))
|
|
elif isinstance(val, float):
|
|
self._dec = _Decimal(repr(val))
|
|
else:
|
|
self._dec = _Decimal(val)
|
|
if mc and hasattr(mc, 'getPrecision') and mc.getPrecision() > 0:
|
|
self._dec = +self._dec
|
|
|
|
@staticmethod
|
|
def valueOf(val):
|
|
if isinstance(val, int):
|
|
if val == 0:
|
|
return BigDecimal.ZERO
|
|
if val == 1:
|
|
return BigDecimal.ONE
|
|
if val == 10:
|
|
return BigDecimal.TEN
|
|
if isinstance(val, float):
|
|
return BigDecimal(repr(val))
|
|
return BigDecimal(val)
|
|
|
|
def add(self, other):
|
|
if isinstance(other, BigDecimal):
|
|
return BigDecimal(self._dec + other._dec)
|
|
return BigDecimal(self._dec + _Decimal(str(other)))
|
|
|
|
def subtract(self, other):
|
|
if isinstance(other, BigDecimal):
|
|
return BigDecimal(self._dec - other._dec)
|
|
return BigDecimal(self._dec - _Decimal(str(other)))
|
|
|
|
def multiply(self, other):
|
|
if isinstance(other, BigDecimal):
|
|
return BigDecimal(self._dec * other._dec)
|
|
return BigDecimal(self._dec * _Decimal(str(other)))
|
|
|
|
def divide(self, *args):
|
|
if len(args) == 1:
|
|
other = args[0]
|
|
if isinstance(other, BigDecimal):
|
|
return BigDecimal(self._dec / other._dec)
|
|
return BigDecimal(self._dec / _Decimal(str(other)))
|
|
elif len(args) == 2:
|
|
other, rounding_mode = args
|
|
if isinstance(other, BigDecimal):
|
|
result = self._dec / other._dec
|
|
else:
|
|
result = self._dec / _Decimal(str(other))
|
|
return BigDecimal(result)
|
|
elif len(args) == 3:
|
|
other, scale, rounding_mode = args
|
|
if isinstance(other, BigDecimal):
|
|
result = self._dec / other._dec
|
|
else:
|
|
result = self._dec / _Decimal(str(other))
|
|
rounded = BigDecimal(result)
|
|
return rounded.setScale(scale, rounding_mode)
|
|
|
|
def divideToIntegralValue(self, other):
|
|
if isinstance(other, BigDecimal):
|
|
return BigDecimal(int(self._dec / other._dec))
|
|
return BigDecimal(int(self._dec / _Decimal(str(other))))
|
|
|
|
def remainder(self, other):
|
|
if isinstance(other, BigDecimal):
|
|
return BigDecimal(self._dec % other._dec)
|
|
return BigDecimal(self._dec % _Decimal(str(other)))
|
|
|
|
def pow(self, n):
|
|
return BigDecimal(self._dec ** n)
|
|
|
|
def abs(self):
|
|
return BigDecimal(abs(self._dec))
|
|
|
|
def negate(self):
|
|
return BigDecimal(-self._dec)
|
|
|
|
def signum(self):
|
|
if self._dec > 0:
|
|
return 1
|
|
if self._dec < 0:
|
|
return -1
|
|
return 0
|
|
|
|
def scale(self):
|
|
return abs(self._dec.as_tuple().exponent)
|
|
|
|
def precision(self):
|
|
return len(self._dec.as_tuple().digits)
|
|
|
|
def round(self, mc):
|
|
if mc.getPrecision() > 0:
|
|
with _local_context() as ctx:
|
|
ctx.prec = mc.getPrecision()
|
|
return BigDecimal(+self._dec)
|
|
return BigDecimal(self._dec)
|
|
|
|
def setScale(self, new_scale, rounding_mode=None):
|
|
if rounding_mode is None:
|
|
qe = _Decimal(10) ** (-new_scale)
|
|
return BigDecimal(self._dec.quantize(qe))
|
|
py_mode = self._round_map.get(rounding_mode, _DEC_ROUND_HALF_UP)
|
|
qe = _Decimal(10) ** (-new_scale)
|
|
return BigDecimal(self._dec.quantize(qe, rounding=py_mode))
|
|
|
|
def ulp(self):
|
|
exponent = self._dec.as_tuple().exponent
|
|
return BigDecimal(_Decimal(10) ** exponent)
|
|
|
|
def unscaledValue(self):
|
|
t = self._dec.as_tuple()
|
|
digits = t.digits
|
|
val = int("".join(str(d) for d in digits))
|
|
return BigInteger(-val if t.sign else val)
|
|
|
|
def byteValueExact(self):
|
|
val = self.intValueExact()
|
|
if val < -128 or val > 127:
|
|
raise ArithmeticError("Overflow")
|
|
return val
|
|
|
|
def shortValueExact(self):
|
|
val = self.intValueExact()
|
|
if val < -32768 or val > 32767:
|
|
raise ArithmeticError("Overflow")
|
|
return val
|
|
|
|
def intValueExact(self):
|
|
if self._dec != int(self._dec):
|
|
raise ArithmeticError("Rounding necessary")
|
|
return int(self._dec)
|
|
|
|
def longValueExact(self):
|
|
if self._dec != int(self._dec):
|
|
raise ArithmeticError("Rounding necessary")
|
|
return int(self._dec)
|
|
|
|
def floatValue(self):
|
|
return float(self._dec)
|
|
|
|
def doubleValue(self):
|
|
return float(self._dec)
|
|
|
|
def intValue(self):
|
|
return int(self._dec)
|
|
|
|
def longValue(self):
|
|
return int(self._dec)
|
|
|
|
def toString(self):
|
|
return str(self._dec)
|
|
|
|
def toEngineeringString(self):
|
|
return format(self._dec, "e")
|
|
|
|
def toPlainString(self):
|
|
return format(self._dec, "f")
|
|
|
|
def compareTo(self, other):
|
|
if isinstance(other, BigDecimal):
|
|
return (self._dec > other._dec) - (self._dec < other._dec)
|
|
return -1
|
|
|
|
def equals(self, other):
|
|
if isinstance(other, BigDecimal):
|
|
return self._dec == other._dec
|
|
return False
|
|
|
|
def hashCode(self):
|
|
return hash(self._dec) & 0x7FFFFFFF
|
|
|
|
def min(self, other):
|
|
return BigDecimal(min(self._dec, other._dec if isinstance(other, BigDecimal) else _Decimal(str(other))))
|
|
|
|
def max(self, other):
|
|
return BigDecimal(max(self._dec, other._dec if isinstance(other, BigDecimal) else _Decimal(str(other))))
|
|
|
|
def __str__(self):
|
|
return str(self._dec)
|
|
|
|
def __int__(self):
|
|
return int(self._dec)
|
|
|
|
def __float__(self):
|
|
return float(self._dec)
|
|
|
|
def __neg__(self):
|
|
return self.negate()
|
|
|
|
def __abs__(self):
|
|
return self.abs()
|
|
|
|
def __add__(self, other):
|
|
return self.add(other)
|
|
|
|
def __sub__(self, other):
|
|
return self.subtract(other)
|
|
|
|
def __mul__(self, other):
|
|
return self.multiply(other)
|
|
|
|
def __truediv__(self, other):
|
|
return self.divide(other)
|
|
|
|
def __mod__(self, other):
|
|
return self.remainder(other)
|
|
|
|
def __pow__(self, other):
|
|
return self.pow(other)
|
|
|
|
|
|
BigDecimal.ZERO = BigDecimal(0)
|
|
BigDecimal.ONE = BigDecimal(1)
|
|
BigDecimal.TEN = BigDecimal(10) |