import com.google.common.annotations.Beta;
import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Strings;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Optional;
// before and after the decimal point. The value zero is represented as
// "0.0".
- final long intPart = intPart();
- final long fracPart = fracPart();
- final StringBuilder sb = new StringBuilder(21);
- if (intPart == 0 && fracPart < 0) {
- sb.append('-');
+ // Pad unscaled value to scale + 1 size string starting after optional '-' sign
+ final var builder = new StringBuilder(21).append(value);
+ final int start = value < 0 ? 1 : 0;
+ final int scale = scale();
+ final int padding = scale + 1 + start - builder.length();
+ if (padding > 0) {
+ builder.insert(start, "0".repeat(padding));
}
- sb.append(intPart).append('.');
- if (fracPart != 0) {
- // We may need to zero-pad the fraction part
- sb.append(Strings.padStart(Long.toString(Math.abs(fracPart)), scale(), '0'));
- } else {
- sb.append('0');
+ // The first digit of the fraction part is now 'scale' from the end. We will insert the decimal point there,
+ // but also we it is the digit we never trim.
+ final int length = builder.length();
+ final int firstDecimal = length - scale;
+
+ // Remove trailing '0's from decimal part. We walk backwards from the last character stop at firstDecimal
+ int significantLength = length;
+ for (int i = length - 1; i > firstDecimal && builder.charAt(i) == '0'; --i) {
+ significantLength = i;
+ }
+ if (significantLength != length) {
+ builder.setLength(significantLength);
}
- return sb.toString();
+ // Insert '.' before the first decimal and we're done
+ return builder.insert(firstDecimal, '.').toString();
}
@Override
assertEquals("-0.63", Decimal64.valueOf("-0.63").toString());
}
+ @Test
+ public void testFractionPartToString() {
+ assertEquals("0.3", Decimal64.valueOf("0.3").toString());
+ assertEquals("0.03", Decimal64.valueOf("0.03").toString());
+ assertEquals("0.003", Decimal64.valueOf("0.003").toString());
+ assertEquals("-0.3", Decimal64.valueOf("-0.3").toString());
+ assertEquals("-0.03", Decimal64.valueOf("-0.03").toString());
+ assertEquals("-0.003", Decimal64.valueOf("-0.003").toString());
+ }
+
+ @Test
+ public void testScalingToString() {
+ assertEquals("30.0", Decimal64.of(1, 300).toString());
+ assertEquals("3.0", Decimal64.of(2, 300).toString());
+ assertEquals("0.3", Decimal64.of(3, 300).toString());
+ assertEquals("0.03", Decimal64.of(4, 300).toString());
+ }
+
@Test
public void testBoundaries() {
assertEquals(-128L, Decimal64.valueOf(1, Byte.MIN_VALUE).longValue());