Skip to content

Instantly share code, notes, and snippets.

@justisr
Created September 7, 2018 18:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save justisr/e00214427fb2f27ec782372d4008a28d to your computer and use it in GitHub Desktop.
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.
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