Clover coverage report - groovy - 1.0-beta-6
Coverage timestamp: Thu Jul 15 2004 13:18:22 BST
file stats: LOC: 242   Methods: 31
NCLOC: 143   Classes: 1
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover
 
 Source file Conditionals Statements Methods TOTAL
NumberMath.java 0% 0% 0% 0%
coverage
 1   
 /*
 2   
  * Created on Mar 7, 2004
 3   
  *
 4   
  */
 5   
 package org.codehaus.groovy.runtime;
 6   
 
 7   
 import java.math.BigDecimal;
 8   
 import java.math.BigInteger;
 9   
 
 10   
 /**
 11   
  * Stateless objects used to perform math on the various Number subclasses.
 12   
  * Instances are required so that polymorphic calls work properly, but each
 13   
  * subclass creates a singleton instance to minimize garbage.  All methods
 14   
  * must be thread-safe.
 15   
  * 
 16   
  * The design goals of this class are as follows:
 17   
  * <ol>
 18   
  * <li>Support a 'least surprising' math model to scripting language users.  This
 19   
  * means that exact, or decimal math should be used for default calculations.  This
 20   
  * scheme assumes that by default, groovy literals with decimal points are instantiated
 21   
  * as BigDecimal objects rather than binary floating points (Float, Double). 
 22   
  * <li>Do not force the appearance of exactness on a number that is by definition not 
 23   
  * guaranteed to be exact.  In particular this means that if an operand in a NumberMath 
 24   
  * operation is a binary floating point number, ensure that the result remains a binary floating point 
 25   
  * number (i.e. never automatically promote a binary floating point number to a BigDecimal).  
 26   
  * This has the effect of preserving the expectations of binary floating point users and helps performance.
 27   
  * <li>Provide an implementation that is as close as practical to the Java 1.5 BigDecimal math model 
 28   
  * which implements precision based floating point decimal math (ANSI X3.274-1996 and 
 29   
  * ANSI X3.274-1996/AM 1-2000 (section 7.4).  
 30   
  * </ol>
 31   
  * 
 32   
  * @author Steve Goetze
 33   
  */
 34   
 public abstract class NumberMath extends Object {
 35   
         
 36  0
     public static Number abs(Number number) {
 37  0
         return getMath(number).absImpl(number);
 38   
     }
 39   
     
 40  0
     public static Number add(Number left, Number right) {
 41  0
         return getMath(left, right).addImpl(left,right);
 42   
     }
 43   
     
 44  0
     public static Number subtract(Number left, Number right) {
 45  0
         return getMath(left,right).subtractImpl(left,right);
 46   
     }
 47   
     
 48  0
     public static Number multiply(Number left, Number right) {
 49  0
         return getMath(left,right).multiplyImpl(left,right);
 50   
     }
 51   
     
 52  0
     public static Number divide(Number left, Number right) {
 53  0
         return getMath(left,right).divideImpl(left,right);
 54   
      }
 55   
       
 56  0
     public static int compareTo(Number left, Number right) {
 57  0
         return getMath(left,right).compareToImpl(left, right);
 58   
     }
 59   
     
 60  0
     public static Number or(Number left, Number right) {
 61  0
         return getMath(left,right).orImpl(left, right);
 62   
     }
 63   
     
 64  0
     public static Number and(Number left, Number right) {
 65  0
         return getMath(left,right).andImpl(left, right);
 66   
     }
 67   
     
 68  0
     public static Number intdiv(Number left, Number right) {
 69  0
         return getMath(left,right).intdivImpl(left,right);
 70   
      }
 71   
 
 72  0
     public static Number mod(Number left, Number right) {
 73  0
         return getMath(left,right).modImpl(left, right);
 74   
     }
 75   
 
 76   
     /**
 77   
      * For this operation, consider the operands independently.  Throw an exception if the right operand
 78   
      * (shift distance) is not an integral type.  For the left operand (shift value) also require an integral
 79   
      * type, but do NOT promote from Integer to Long.  This is consistent with Java, and makes sense for the
 80   
      * shift operators.
 81   
      */
 82  0
     public static Number leftShift(Number left, Number right) {
 83  0
         if (isFloatingPoint(right) || isBigDecimal(right)) {
 84  0
             throw new UnsupportedOperationException("Shift distance must be an integral type, but " +  right + " (" + right.getClass().getName() + ") was supplied");
 85   
         }
 86  0
         return getMath(left).leftShiftImpl(left,right);
 87   
     }
 88   
     
 89   
     /**
 90   
      * For this operation, consider the operands independently.  Throw an exception if the right operand
 91   
      * (shift distance) is not an integral type.  For the left operand (shift value) also require an integral
 92   
      * type, but do NOT promote from Integer to Long.  This is consistent with Java, and makes sense for the
 93   
      * shift operators.
 94   
      */
 95  0
     public static Number rightShift(Number left, Number right) {
 96  0
         if (isFloatingPoint(right) || isBigDecimal(right)) {
 97  0
             throw new UnsupportedOperationException("Shift distance must be an integral type, but " +  right + " (" + right.getClass().getName() + ") was supplied");
 98   
         }
 99  0
         return getMath(left).rightShiftImpl(left,right);
 100   
     }
 101   
     
 102   
     /**
 103   
      * For this operation, consider the operands independently.  Throw an exception if the right operand
 104   
      * (shift distance) is not an integral type.  For the left operand (shift value) also require an integral
 105   
      * type, but do NOT promote from Integer to Long.  This is consistent with Java, and makes sense for the
 106   
      * shift operators.
 107   
      */
 108  0
     public static Number rightShiftUnsigned(Number left, Number right) {
 109  0
         if (isFloatingPoint(right) || isBigDecimal(right)) {
 110  0
             throw new UnsupportedOperationException("Shift distance must be an integral type, but " +  right + " (" + right.getClass().getName() + ") was supplied");
 111   
         }
 112  0
         return getMath(left).rightShiftUnsignedImpl(left,right);
 113   
     }
 114   
     
 115  0
     public static Number negate(Number left) {
 116  0
         return getMath(left).negateImpl(left);
 117   
     }
 118   
     
 119  0
     public static boolean isFloatingPoint(Number number) {
 120  0
         return number instanceof Double || number instanceof Float;
 121   
     }
 122   
 
 123  0
     public static boolean isInteger(Number number) {
 124  0
         return number instanceof Integer;
 125   
     }
 126   
 
 127  0
     public static boolean isLong(Number number) {
 128  0
         return number instanceof Long;
 129   
     }
 130   
 
 131  0
     public static boolean isBigDecimal(Number number) {
 132  0
         return number instanceof BigDecimal;
 133   
     }
 134   
 
 135  0
     public static boolean isBigInteger(Number number) {
 136  0
         return number instanceof BigInteger;
 137   
     }
 138   
 
 139  0
     public static BigDecimal toBigDecimal(Number n) {
 140  0
         return (n instanceof BigDecimal ? (BigDecimal) n : new BigDecimal(n.toString()));
 141   
     }
 142   
                 
 143  0
     public static BigInteger toBigInteger(Number n) {
 144  0
         return (n instanceof BigInteger ? (BigInteger) n : new BigInteger(n.toString()));
 145   
     }
 146   
                     
 147   
     /**
 148   
      * Determine which NumberMath instance to use, given the supplied operands.  This method implements
 149   
      * the type promotion rules discussed in the documentation.  Note that by the time this method is
 150   
      * called, any Byte, Character or Short operands will have been promoted to Integer.  For reference,
 151   
      * here is the promotion matrix:
 152   
      *    bD bI  D  F  L  I
 153   
      * bD bD bD  D  D bD bD
 154   
      * bI bD bI  D  D bI bI
 155   
      *  D  D  D  D  D  D  D
 156   
      *  F  D  D  D  D  D  D
 157   
      *  L bD bI  D  D  L  L
 158   
      *  I bD bI  D  D  L  I
 159   
      * 
 160   
      * Note that for division, if either operand isFloatingPoint, the result will be floating.  Otherwise,
 161   
      * the result is BigDecimal
 162   
      */
 163  0
     private static NumberMath getMath(Number left, Number right) {
 164  0
         if (isFloatingPoint(left) || isFloatingPoint(right)) {
 165  0
             return FloatingPointMath.instance;
 166   
         }
 167  0
         else if (isBigDecimal(left) || isBigDecimal(right)) {
 168  0
             return BigDecimalMath.instance;
 169   
         }
 170  0
         else if (isBigInteger(left) || isBigInteger(right)) {
 171  0
             return BigIntegerMath.instance;
 172   
         }
 173  0
         else if (isLong(left) || isLong(right)){
 174  0
             return LongMath.instance;
 175   
         }
 176  0
         return IntegerMath.instance;
 177   
     }
 178   
 
 179  0
     private static NumberMath getMath(Number number) {
 180  0
         if (isInteger(number)) {
 181  0
             return IntegerMath.instance;
 182   
         }
 183  0
         else if (isLong(number)) {
 184  0
             return LongMath.instance;
 185   
         }
 186  0
         else if (isFloatingPoint(number)) {
 187  0
             return FloatingPointMath.instance;
 188   
         }            
 189  0
         else if (isBigDecimal(number)) {
 190  0
             return BigDecimalMath.instance;
 191   
         }
 192  0
         else if (isBigInteger(number)) {
 193  0
             return BigIntegerMath.instance;
 194   
         }
 195   
         else {
 196  0
             throw new IllegalArgumentException("An unexpected Number subclass was supplied.");
 197   
         }
 198   
     }
 199   
     
 200   
     //Subclasses implement according to the type promotion hierarchy rules
 201   
     protected abstract Number absImpl(Number number);
 202   
     protected abstract Number addImpl(Number left, Number right);
 203   
     protected abstract Number subtractImpl(Number left, Number right);
 204   
     protected abstract Number multiplyImpl(Number left, Number right);
 205   
     protected abstract Number divideImpl(Number left, Number right);
 206   
     protected abstract int compareToImpl(Number left, Number right);
 207   
     protected abstract Number negateImpl(Number left);
 208   
 
 209   
 
 210  0
     protected Number andImpl(Number left, Number right) {
 211  0
         throw createUnsupportedException("and()", left);
 212   
     }
 213   
 
 214  0
     protected Number modImpl(Number left, Number right) {
 215  0
         throw createUnsupportedException("mod()", left);
 216   
     }
 217   
     
 218  0
     protected Number intdivImpl(Number left, Number right) {
 219  0
         throw createUnsupportedException("intdiv()", left);
 220   
     }
 221   
     
 222  0
     protected Number orImpl(Number left, Number right) {
 223  0
         throw createUnsupportedException("or()", left);
 224   
     }
 225   
     
 226  0
     protected Number leftShiftImpl(Number left, Number right) {
 227  0
         throw createUnsupportedException("leftShift()", left);
 228   
     }
 229   
 
 230  0
     protected Number rightShiftImpl(Number left, Number right) {
 231  0
         throw createUnsupportedException("rightShift()", left);
 232   
     }
 233   
 
 234  0
     protected Number rightShiftUnsignedImpl(Number left, Number right) {
 235  0
         throw createUnsupportedException("rightShiftUnsigned()", left);
 236   
     }
 237   
 
 238  0
     protected UnsupportedOperationException createUnsupportedException(String operation, Number left) {
 239  0
         return new UnsupportedOperationException("Cannot use " + operation + " on this number type: " + left.getClass().getName() + " with value: " + left);
 240   
     }
 241   
 }
 242