001 package org.codehaus.groovy.runtime.typehandling; 002 003 import java.math.BigDecimal; 004 005 /** 006 * BigDecimal NumberMath operations 007 * 008 * @author Steve Goetze 009 */ 010 public class BigDecimalMath extends NumberMath { 011 012 //This is an arbitrary value, picked as a reasonable choice for a rounding point 013 //for typical user math. 014 public static final int MAX_DIVISION_SCALE = 10; 015 016 protected static BigDecimalMath instance = new BigDecimalMath(); 017 018 private BigDecimalMath() {} 019 020 protected Number absImpl(Number number) { 021 return toBigDecimal(number).abs(); 022 } 023 024 protected Number addImpl(Number left, Number right) { 025 return toBigDecimal(left).add(toBigDecimal(right)); 026 } 027 028 protected Number subtractImpl(Number left, Number right) { 029 return toBigDecimal(left).subtract(toBigDecimal(right)); 030 } 031 032 protected Number multiplyImpl(Number left, Number right) { 033 return toBigDecimal(left).multiply(toBigDecimal(right)); 034 } 035 036 protected Number divideImpl(Number left, Number right) { 037 //Hack until Java 1.5 BigDecimal is available. For now, pick 038 //a result scale which is the maximum of the scale of the 039 //two operands and an arbitrary maximum (similar to what a 040 //handheld calculator would do). Then, normalize the result 041 //by removing any trailing zeros. 042 BigDecimal bigLeft = toBigDecimal(left); 043 BigDecimal bigRight = toBigDecimal(right); 044 int scale = Math.max(bigLeft.scale(), bigRight.scale()); 045 return normalize(bigLeft.divide(bigRight, Math.max(scale, MAX_DIVISION_SCALE), BigDecimal.ROUND_HALF_UP)); 046 } 047 048 protected int compareToImpl(Number left, Number right) { 049 return toBigDecimal(left).compareTo(toBigDecimal(right)); 050 } 051 052 private BigDecimal normalize(BigDecimal number) { 053 // we have to take care of the case number==0, because 0 can have every 054 // scale and the test in the while loop would never end 055 if (number.signum()==0) { 056 // the smallest scale for 0 is 0 057 return number.setScale(0); 058 } 059 // rescale until we found the smallest possible scale 060 try { 061 while (true) { 062 number = number.setScale(number.scale()-1); 063 } 064 } catch (ArithmeticException e) { 065 return number; 066 } 067 } 068 069 protected Number negateImpl(Number left) { 070 return toBigDecimal(left).negate(); 071 } 072 }