Created
September 7, 2018 18:53
-
-
Save justisr/e00214427fb2f27ec782372d4008a28d to your computer and use it in GitHub Desktop.
BigDecimal wrapper which prioritizes the re-use of existing instances and removes trailing zeros.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.math.BigDecimal; | |
import java.math.RoundingMode; | |
import java.util.concurrent.ConcurrentMap; | |
import com.google.common.collect.MapMaker; | |
public class Unit { | |
private static ConcurrentMap<String, Unit> POOL = new MapMaker().weakValues().concurrencyLevel(1).initialCapacity(666).makeMap(); | |
public static final Unit NEG_ONE = get("-1"); | |
public static final Unit ZERO = get("0"); | |
public static final Unit ONE = get("1"); | |
public static final Unit TWO = get("2"); | |
public static final Unit TEN = get("10"); | |
private static int scale = 20; | |
public static final Unit get(String val) { | |
val = trimZeros(val); | |
Unit big = POOL.get(val); | |
if (big != null) return big; | |
big = valueOf(val); | |
if (big == null) return null; | |
POOL.put(val, big); | |
return big; | |
} | |
public static final Unit get(Object val) { | |
return get(val.toString()); | |
} | |
private final BigDecimal bd; | |
private Unit(String string) { | |
this.bd = new BigDecimal(string); | |
} | |
public Unit add(Unit augend) { | |
return get(bd.add(augend.bd).toPlainString()); | |
} | |
public Unit subtract(Unit subtrahend) { | |
return get(bd.subtract(subtrahend.bd).toPlainString()); | |
} | |
public Unit multiply(Unit multiplicand) { | |
return get(bd.multiply(multiplicand.bd).toPlainString()); | |
} | |
public Unit divide(Unit divisor) { | |
return get(bd.divide(divisor.bd, scale, RoundingMode.HALF_EVEN).toPlainString()); | |
} | |
public Unit pow(int i) { | |
return get(bd.pow(i).toPlainString()); | |
} | |
public boolean greaterThan(Unit val) { | |
return bd.compareTo(val.bd) > 0; | |
} | |
public boolean lessThan(Unit val) { | |
return bd.compareTo(val.bd) < 0; | |
} | |
public boolean equals(Unit val) { | |
return bd.compareTo(val.bd) == 0; | |
} | |
public int signum() { | |
return bd.signum(); | |
} | |
@Override | |
public String toString() { | |
return bd.toPlainString(); | |
} | |
public static void setScale(int scale) { | |
Unit.scale = scale; | |
} | |
/** | |
* Remove all trailing decimal zeros with a worst possible performance of only O(n) and best of O(1) where n is the length of the string.<br> | |
* Will return the string immediately if the length is less than three or if the last character is not 0.<br> | |
* Otherwise, it will iterate backward through the provided string removing zeros until a whole number is found, then it will return once the decimal is verified.<br> | |
* If the full string is processed and no decimal is found, it will return the original string, knowing the removed 0s to have not been trailing decimal zeros. | |
* @param s String to remove trailing decimal zeros. | |
* @return as string version of the provided string without trailing decimal zeros. | |
*/ | |
private static final String trimZeros(String s) { | |
if (s.length() < 3 || s.charAt(s.length()-1) != '0') return s; | |
int trim = 1; | |
boolean foundNonZero = false; | |
for (int i = s.length()-2; i > 0; i--) { | |
if (!foundNonZero && s.charAt(i) == '0') | |
trim++; | |
else if (s.charAt(i) == '.') { | |
if (!foundNonZero) trim++; | |
StringBuilder sb = new StringBuilder(s); | |
sb.setLength(s.length() - trim); | |
return sb.toString(); | |
} else foundNonZero = true; | |
} | |
return s; | |
} | |
private static final Unit valueOf(String string) { | |
try { | |
return new Unit(string); | |
} catch (NumberFormatException e) { } | |
return null; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment