package er.extensions.foundation; import java.math.BigDecimal; import er.extensions.enums.ERXMoneyEnums; /** * * @author ishimoto */ public class ERXMoney { //******************************************************************** // プロパティ //******************************************************************** protected long value; protected ERXMoneyEnums money; //******************************************************************** // コンストラクタ //******************************************************************** protected ERXMoney() {} public ERXMoney(final ERXMoney x) { value = x.value; } public ERXMoney(final BigDecimal x, ERXMoneyEnums currency) { this(x.doubleValue(), currency); } public ERXMoney(final double x, ERXMoneyEnums currency) { value = Math.round(x * currency.scale()); this.money = currency; } //******************************************************************** // Pseudo assignment operators //******************************************************************** public ERXMoney set(final double rs) { value = Math.round(rs * money.scale()); return this; } public ERXMoney set(final BigDecimal rs) { value = Math.round(rs.doubleValue() * money.scale()); return this; } public ERXMoney set(final ERXMoney rs) { value = rs.value; return this; } //******************************************************************** // Accessors //******************************************************************** public long wholeUnits() { return value / money.scale(); } public short cents() { return (short) ((value * 100) / money.scale() - (100 * wholeUnits())); } public BigDecimal asBigDecimal() { int centScale = log10(money.scale()); String centString = "00000000" + cents(); return new BigDecimal(wholeUnits() + "." + centString.substring(centString.length() - centScale, centString.length())); } //******************************************************************** // Numeric utility functions //******************************************************************** public ERXMoney abs() { ERXMoney result = new ERXMoney(this); if (value < 0) result.value = - result.value; return result; } public short sign() { return (short) (value > 0 ? 1 : value < 0 ? -1 : 0); } //******************************************************************** // Relational (predicate) operations //******************************************************************** public boolean equals(final ERXMoney rs) { return value == rs.value; } public boolean lessThan(final ERXMoney rs) { return value < rs.value; } public boolean greaterThan(final ERXMoney rs) { return value > rs.value; } public boolean equals(final double rs) { return value == rs * money.scale(); } public boolean lessThan(final double rs) { return value < rs * money.scale(); } public boolean greaterThan(final double rs) { return value > rs * money.scale(); } //******************************************************************** // These three functions are to comply with Java library conventions //******************************************************************** @Override public boolean equals(final Object rs) { return (rs instanceof ERXMoney) && (((ERXMoney) rs).value == value); } public int compareTo(final Object rs) { return sub((ERXMoney) rs).sign(); } @Override public int hashCode() { return (Long.valueOf(value)).hashCode(); } //******************************************************************** // Arithmetic operations //******************************************************************** public ERXMoney addSet(final ERXMoney rs) { value += rs.value; return this; } public ERXMoney addSet(final double rs) { value += rs * money.scale(); return this; } public ERXMoney addSet(final BigDecimal rs) { value += rs.doubleValue() * money.scale(); return this; } public ERXMoney subSet(final ERXMoney rs) { value -= rs.value; return this; } public ERXMoney subSet(final double rs){ value -= rs * money.scale(); return this; } public ERXMoney subSet(final BigDecimal rs){ value -= rs.doubleValue() * money.scale(); return this; } public ERXMoney mpySet(final ERXMoney rs) { value *= rs.value; return this; } public ERXMoney mpySet(final double rs) { value *= rs; return this; } public ERXMoney mpySet(final BigDecimal rs) { value *= rs.doubleValue(); return this; } public ERXMoney divSet(final ERXMoney rs) { value = Math.round(value / rs.value); return this; } public ERXMoney divSet(final double rs) { value = Math.round(value / rs); return this; } public ERXMoney divSet(final BigDecimal rs) { value = Math.round(value / rs.doubleValue()); return this; } public ERXMoney percentSet(final double rs) { value = Math.round((double) value / 100 * rs); return this; } public ERXMoney percentSet(final BigDecimal rs) { value = Math.round((double) value / 100 * rs.doubleValue()); return this; } public ERXMoney minusSet() { value = - value; return this; } public ERXMoney add(final ERXMoney rs) { return new ERXMoney(this).addSet(rs); } public ERXMoney add(final double rs) { return new ERXMoney(this).addSet(rs); } public ERXMoney sub(final ERXMoney rs) { return new ERXMoney(this).subSet(rs); } public ERXMoney sub(final double rs) { return new ERXMoney(this).subSet(rs); } public ERXMoney mpy(final ERXMoney rs) { return new ERXMoney(this).mpySet(rs); } public ERXMoney mpy(final double rs) { return new ERXMoney(this).mpySet(rs); } public ERXMoney div(final ERXMoney rs) { return new ERXMoney(this).divSet(rs); } public ERXMoney div(final double rs) { return new ERXMoney(this).divSet(rs); } public ERXMoney minus() { return new ERXMoney(this).minusSet(); } //******************************************************************** // Conversion functions //******************************************************************** private static short log10(long x) { short result; // of decimal digits in an integer for (result=0; x>=10; result++, x/=10) { // Decimal "shift" and count } return result; } @Override public String toString() { boolean negative = (value < 0); // Remember original sign value = negative ? -value : value; // Discard sign temporarily long whole = wholeUnits(); // Separate arg. into whole short cents = cents(); // and fractional monetary units short rest = (short) (value - (cents + 100 * whole) * money.scale() / 100); String result = (negative ? "-" : ""); // Insert prefix minus, if needed result = result + money.prefixSymbol(); // Insert dollar sign or equiv. long divisors[] = { 1, 1000, 1000000, (long) 1E9, (long) 1E12,(long) 1E15, (long) 1E18 }; int group_no = log10(whole) / 3; int group_val = (int)(whole / divisors[group_no]); result = result + group_val; // Append leftmost 3-digits while (group_no > 0) { // For each remaining 3-digit group result = result + money.group_separator(); // Insert punctuation whole -= group_val * divisors[group_no--]; // Compute new remainder group_val = (short) (whole/divisors[group_no]); // Get next 3-digit value if (group_val < 100) { result = result + "0"; // Insert embedded 0's } if (group_val < 10) { result = result + "0"; // as needed } result = result + group_val; // Append group value } // Append the fractional portion if(money.scale() > 1) { result = result + money.decimal_point(); // Append decimal point int centScale = log10(money.scale()); String centString = "00000000" + cents; // Append cents value result += centString.substring(centString.length() - centScale, centString.length()); } if (rest > 0) { // Test for fractional pennies while ((rest *= 10) < money.scale()) { // (rest *= power(10,log10(money.scale()))) } result = result + (rest/money.scale()); // Append fractional pennies, if any } if (negative) { // Restore original sign value = - value; } return result + money.suffixSymbol(); // Append final symbol, if any } }