Class NumberMath

java.lang.Object
org.codehaus.groovy.runtime.typehandling.NumberMath
Direct Known Subclasses:
BigDecimalMath, BigIntegerMath, FloatingPointMath, IntegerMath, LongMath

public abstract class NumberMath extends Object
Stateless objects used to perform math on the various Number subclasses. Instances are required so that polymorphic calls work properly, but each subclass creates a singleton instance to minimize garbage. All methods must be thread-safe. The design goals of this class are as follows:
  1. Support a 'least surprising' math model to scripting language users. This means that exact, or decimal math should be used for default calculations. This scheme assumes that by default, groovy literals with decimal points are instantiated as BigDecimal objects rather than binary floating points (Float, Double).
  2. Do not force the appearance of exactness on a number that is by definition not guaranteed to be exact. In particular this means that if an operand in a NumberMath operation is a binary floating point number, ensure that the result remains a binary floating point number (i.e. never automatically promote a binary floating point number to a BigDecimal). This has the effect of preserving the expectations of binary floating point users and helps performance.
  3. Provide an implementation that is as close as practical to the Java 1.5 BigDecimal math model which implements precision based floating point decimal math (ANSI X3.274-1996 and ANSI X3.274-1996/AM 1-2000 (section 7.4).
  • Constructor Details

    • NumberMath

      public NumberMath()
  • Method Details

    • abs

      public static Number abs(Number number)
      Computes the absolute value of a number using its specific type's math operations.
      Parameters:
      number - the number (must not be null)
      Returns:
      the absolute value using the appropriate NumberMath instance
    • add

      public static Number add(Number left, Number right)
      Adds two numbers using type promotion rules.
      Parameters:
      left - the left operand
      right - the right operand
      Returns:
      the sum using the appropriate NumberMath instance
    • subtract

      public static Number subtract(Number left, Number right)
      Subtracts two numbers using type promotion rules.
      Parameters:
      left - the minuend
      right - the subtrahend
      Returns:
      the difference using the appropriate NumberMath instance
    • multiply

      public static Number multiply(Number left, Number right)
      Multiplies two numbers using type promotion rules.
      Parameters:
      left - the first multiplicand
      right - the second multiplicand
      Returns:
      the product using the appropriate NumberMath instance
    • divide

      public static Number divide(Number left, Number right)
      Divides two numbers using type promotion rules.

      For floating-point operands, performs binary floating-point division. For integral types, delegates to BigDecimal division for exact results.

      Parameters:
      left - the dividend
      right - the divisor
      Returns:
      the quotient using the appropriate NumberMath instance
      Throws:
      ArithmeticException - if right is zero
    • compareTo

      public static int compareTo(Number left, Number right)
      Compares two numbers using type promotion rules.
      Parameters:
      left - the first number
      right - the second number
      Returns:
      a negative, zero, or positive int as left is less than, equal to, or greater than right
    • or

      public static Number or(Number left, Number right)
      Bitwise OR operation on two integral numbers.
      Parameters:
      left - the first operand
      right - the second operand
      Returns:
      the bitwise OR result
      Throws:
      UnsupportedOperationException - if operands are not integral types
    • and

      public static Number and(Number left, Number right)
      Bitwise AND operation on two integral numbers.
      Parameters:
      left - the first operand
      right - the second operand
      Returns:
      the bitwise AND result
      Throws:
      UnsupportedOperationException - if operands are not integral types
    • xor

      public static Number xor(Number left, Number right)
      Bitwise XOR operation on two integral numbers.
      Parameters:
      left - the first operand
      right - the second operand
      Returns:
      the bitwise XOR result
      Throws:
      UnsupportedOperationException - if operands are not integral types
    • intdiv

      public static Number intdiv(Number left, Number right)
      Integer division (without remainder) of two numbers.

      For BigInteger and integral types, performs exact integer division. For floating-point operands, delegates to FloatingPointMath.

      Parameters:
      left - the dividend
      right - the divisor
      Returns:
      the integer quotient
      Throws:
      UnsupportedOperationException - if operands don't support integer division
    • mod

      public static Number mod(Number left, Number right)
      Modulo operation on two numbers (for backwards compatibility).

      This method is retained for backwards compatibility

      Parameters:
      left - the dividend
      right - the divisor
      Returns:
      the modulo result
    • remainder

      public static Number remainder(Number left, Number right)
      Remainder operation on two numbers.

      Returns the remainder after integer division.

      Parameters:
      left - the dividend
      right - the divisor
      Returns:
      the remainder
      Throws:
      UnsupportedOperationException - if operands don't support remainder operation
    • leftShift

      public static Number leftShift(Number left, Number right)
      Left shift operation on integral numbers.

      The shift distance (right operand) must be an integral type. The value to shift (left operand) must also be integral.

      Parameters:
      left - the value to shift (must be integral)
      right - the shift distance (must be integral)
      Returns:
      the left-shifted value
      Throws:
      UnsupportedOperationException - if shift distance is floating-point or BigDecimal
    • rightShift

      public static Number rightShift(Number left, Number right)
      Right shift operation on integral numbers.

      The shift distance (right operand) must be an integral type. The value to shift (left operand) must also be integral.

      Parameters:
      left - the value to shift (must be integral)
      right - the shift distance (must be integral)
      Returns:
      the right-shifted value
      Throws:
      UnsupportedOperationException - if shift distance is floating-point or BigDecimal
    • rightShiftUnsigned

      public static Number rightShiftUnsigned(Number left, Number right)
      Unsigned right shift operation on integral numbers.

      The shift distance (right operand) must be an integral type. The value to shift (left operand) must also be integral.

      Parameters:
      left - the value to shift (must be integral)
      right - the shift distance (must be integral)
      Returns:
      the unsigned right-shifted value
      Throws:
      UnsupportedOperationException - if shift distance is floating-point or BigDecimal
    • bitwiseNegate

      public static Number bitwiseNegate(Number left)
      Bitwise negation (complement) of an integral number.
      Parameters:
      left - the operand (must be integral)
      Returns:
      the bitwise negation
      Throws:
      UnsupportedOperationException - if operand is not integral
    • unaryMinus

      public static Number unaryMinus(Number left)
      Unary negation of a number.
      Parameters:
      left - the operand
      Returns:
      the negation
    • unaryPlus

      public static Number unaryPlus(Number left)
      Unary plus (identity) operation on a number.
      Parameters:
      left - the operand
      Returns:
      the same value
    • isFloatingPoint

      public static boolean isFloatingPoint(Number number)
      Tests whether a number is a floating-point type (Float or Double).
      Parameters:
      number - the number to test
      Returns:
      true if the number is Float or Double
    • isInteger

      public static boolean isInteger(Number number)
      Tests whether a number is an Integer.
      Parameters:
      number - the number to test
      Returns:
      true if the number is an Integer
    • isShort

      public static boolean isShort(Number number)
      Tests whether a number is a Short.
      Parameters:
      number - the number to test
      Returns:
      true if the number is a Short
    • isByte

      public static boolean isByte(Number number)
      Tests whether a number is a Byte.
      Parameters:
      number - the number to test
      Returns:
      true if the number is a Byte
    • isLong

      public static boolean isLong(Number number)
      Tests whether a number is a Long.
      Parameters:
      number - the number to test
      Returns:
      true if the number is a Long
    • isBigDecimal

      public static boolean isBigDecimal(Number number)
      Tests whether a number is a BigDecimal.
      Parameters:
      number - the number to test
      Returns:
      true if the number is a BigDecimal
    • isBigInteger

      public static boolean isBigInteger(Number number)
      Tests whether a number is a BigInteger.
      Parameters:
      number - the number to test
      Returns:
      true if the number is a BigInteger
    • toBigDecimal

      public static BigDecimal toBigDecimal(Number n)
      Converts a number to a BigDecimal.

      Handles BigDecimal, BigInteger, integral types, and floating-point types. Floating-point numbers are converted via their string representation to preserve precision.

      Parameters:
      n - the number to convert (must not be null)
      Returns:
      a BigDecimal representation of the number
    • toBigInteger

      public static BigInteger toBigInteger(Number n)
      Converts a number to a BigInteger.

      Handles BigInteger, integral types, floating-point types, and BigDecimal. Floating-point numbers are first converted to BigDecimal before extraction.

      Parameters:
      n - the number to convert (must not be null)
      Returns:
      a BigInteger representation of the number
    • getMath

      public static NumberMath getMath(Number left, Number right)
      Determines which NumberMath instance to use for binary operations on two operands.

      Implements the type promotion matrix:

          bD bI  D  F  L  I
       bD bD bD  D  D bD bD
       bI bD bI  D  D bI bI
        D  D  D  D  D  D  D
        F  D  D  D  D  D  D
        L bD bI  D  D  L  L
        I bD bI  D  D  L  I
       

      Where: bD=BigDecimal, bI=BigInteger, D=Double, F=Float, L=Long, I=Integer

      Note: Byte, Character, and Short operands are pre-promoted to Integer. For division, if either operand is floating-point, the result is floating-point. Otherwise, the result is BigDecimal.

      Parameters:
      left - the left operand
      right - the right operand
      Returns:
      the appropriate NumberMath instance for these operands
    • absImpl

      protected abstract Number absImpl(Number number)
      Computes the absolute value of a number.

      Subclasses must implement this method according to type promotion hierarchy rules.

      Parameters:
      number - the operand
      Returns:
      the absolute value
    • addImpl

      public abstract Number addImpl(Number left, Number right)
      Adds two numbers.

      Subclasses must implement this method according to type promotion hierarchy rules.

      Parameters:
      left - the left operand
      right - the right operand
      Returns:
      the sum
    • subtractImpl

      public abstract Number subtractImpl(Number left, Number right)
      Subtracts two numbers.

      Subclasses must implement this method according to type promotion hierarchy rules.

      Parameters:
      left - the minuend
      right - the subtrahend
      Returns:
      the difference
    • multiplyImpl

      public abstract Number multiplyImpl(Number left, Number right)
      Multiplies two numbers.

      Subclasses must implement this method according to type promotion hierarchy rules.

      Parameters:
      left - the first multiplicand
      right - the second multiplicand
      Returns:
      the product
    • divideImpl

      public abstract Number divideImpl(Number left, Number right)
      Divides two numbers.

      Subclasses must implement this method according to type promotion hierarchy rules.

      Parameters:
      left - the dividend
      right - the divisor
      Returns:
      the quotient
    • compareToImpl

      public abstract int compareToImpl(Number left, Number right)
      Compares two numbers.

      Subclasses must implement this method according to type promotion hierarchy rules.

      Parameters:
      left - the first number
      right - the second number
      Returns:
      negative, zero, or positive as left is less than, equal to, or greater than right
    • unaryMinusImpl

      protected abstract Number unaryMinusImpl(Number left)
      Negates a number.

      Subclasses must implement this method according to type promotion hierarchy rules.

      Parameters:
      left - the operand
      Returns:
      the negation
    • unaryPlusImpl

      protected abstract Number unaryPlusImpl(Number left)
      Returns the number as-is (unary plus/identity).

      Subclasses must implement this method according to type promotion hierarchy rules.

      Parameters:
      left - the operand
      Returns:
      the same value
    • bitwiseNegateImpl

      protected Number bitwiseNegateImpl(Number left)
      Bitwise negation of a number.

      Default implementation throws UnsupportedOperationException. Subclasses supporting bitwise operations must override.

      Parameters:
      left - the operand
      Returns:
      the bitwise negation
      Throws:
      UnsupportedOperationException - if not supported for this type
    • orImpl

      protected Number orImpl(Number left, Number right)
      Bitwise OR of two numbers.

      Default implementation throws UnsupportedOperationException. Subclasses supporting bitwise operations must override.

      Parameters:
      left - the first operand
      right - the second operand
      Returns:
      the bitwise OR result
      Throws:
      UnsupportedOperationException - if not supported for this type
    • andImpl

      protected Number andImpl(Number left, Number right)
      Bitwise AND of two numbers.

      Default implementation throws UnsupportedOperationException. Subclasses supporting bitwise operations must override.

      Parameters:
      left - the first operand
      right - the second operand
      Returns:
      the bitwise AND result
      Throws:
      UnsupportedOperationException - if not supported for this type
    • xorImpl

      protected Number xorImpl(Number left, Number right)
      Bitwise XOR of two numbers.

      Default implementation throws UnsupportedOperationException. Subclasses supporting bitwise operations must override.

      Parameters:
      left - the first operand
      right - the second operand
      Returns:
      the bitwise XOR result
      Throws:
      UnsupportedOperationException - if not supported for this type
    • remainderImpl

      protected Number remainderImpl(Number left, Number right)
      Remainder of two numbers.

      Default implementation throws UnsupportedOperationException. Subclasses supporting remainder must override.

      Parameters:
      left - the dividend
      right - the divisor
      Returns:
      the remainder
      Throws:
      UnsupportedOperationException - if not supported for this type
    • modImpl

      protected Number modImpl(Number left, Number right)
      Modulo of two numbers.

      Default implementation throws UnsupportedOperationException. Subclasses supporting modulo must override.

      Parameters:
      left - the dividend
      right - the divisor
      Returns:
      the modulo result
      Throws:
      UnsupportedOperationException - if not supported for this type
    • intdivImpl

      protected Number intdivImpl(Number left, Number right)
      Integer division of two numbers.

      Default implementation throws UnsupportedOperationException. Subclasses supporting integer division must override.

      Parameters:
      left - the dividend
      right - the divisor
      Returns:
      the integer quotient
      Throws:
      UnsupportedOperationException - if not supported for this type
    • leftShiftImpl

      protected Number leftShiftImpl(Number left, Number right)
      Left shift of a number.

      Default implementation throws UnsupportedOperationException. Subclasses supporting bit shifting must override.

      Parameters:
      left - the value to shift
      right - the shift distance
      Returns:
      the left-shifted value
      Throws:
      UnsupportedOperationException - if not supported for this type
    • rightShiftImpl

      protected Number rightShiftImpl(Number left, Number right)
      Right shift of a number.

      Default implementation throws UnsupportedOperationException. Subclasses supporting bit shifting must override.

      Parameters:
      left - the value to shift
      right - the shift distance
      Returns:
      the right-shifted value
      Throws:
      UnsupportedOperationException - if not supported for this type
    • rightShiftUnsignedImpl

      protected Number rightShiftUnsignedImpl(Number left, Number right)
      Unsigned right shift of a number.

      Default implementation throws UnsupportedOperationException. Subclasses supporting bit shifting must override.

      Parameters:
      left - the value to shift
      right - the shift distance
      Returns:
      the unsigned right-shifted value
      Throws:
      UnsupportedOperationException - if not supported for this type
    • createUnsupportedException

      protected UnsupportedOperationException createUnsupportedException(String operation, Number left)
      Creates an UnsupportedOperationException for an unsupported operation.
      Parameters:
      operation - the name of the unsupported operation
      left - the operand
      Returns:
      a new UnsupportedOperationException