""" 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)