*/
public void roundToInfinity();
+ /**
+ * Truncates the decimals from this DecimalQuantity. Equivalent to calling roundToMagnitude(0, FLOOR)
+ */
+ void truncate();
+
/**
* Multiply the internal value.
*
}
}
+ @Override
+ public void truncate() {
+ if (scale < 0) {
+ shiftRight(-scale);
+ scale = 0;
+ compact();
+ }
+ }
+
/**
* Appends a digit, optionally with one or more leading zeros, to the end of the value represented
* by this DecimalQuantity.
// License & terms of use: http://www.unicode.org/copyright.html#License
package com.ibm.icu.impl.number.parse;
+import java.util.Collection;
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;
public static void generateFromPatternModifier(
MutablePatternModifier patternModifier,
int flags,
+ boolean includeUnpaired,
NumberParserImpl output) {
// Store the matchers in a TreeSet to ensure both uniqueness and order.
if (patternModifier.needsPlurals()) {
for (StandardPlural plural : StandardPlural.VALUES) {
patternModifier.setNumberProperties(isNegative, plural);
- matchers.add(getInstance(patternModifier, flags, nsb));
+ AffixMatcher.createAndAppendTo(matchers, patternModifier, flags, nsb, includeUnpaired);
}
} else {
patternModifier.setNumberProperties(isNegative, null);
- matchers.add(getInstance(patternModifier, flags, nsb));
+ AffixMatcher.createAndAppendTo(matchers, patternModifier, flags, nsb, includeUnpaired);
}
if (isNegative) {
}
/**
- * Constructs an AffixMatcher from the given MutablePatternModifier and flags. The NumberStringBuilder is used as a
- * temporary object only.
+ * Constructs one or more AffixMatchers from the given MutablePatternModifier and flags, appending them to the given
+ * collection. The NumberStringBuilder is used as a temporary object only.
+ *
+ * @param includeUnpaired If true, create additional AffixMatchers with an unpaired prefix or suffix.
*/
- private static AffixMatcher getInstance(
+ private static void createAndAppendTo(
+ Collection<AffixMatcher> appendTo,
MutablePatternModifier patternModifier,
int flags,
- NumberStringBuilder nsb) {
+ NumberStringBuilder nsb,
+ boolean includeUnpaired) {
// TODO: Make this more efficient (avoid the substrings and things)
nsb.clear();
patternModifier.apply(nsb, 0, 0);
String full = nsb.toString();
String prefix = full.substring(0, prefixLength);
String suffix = full.substring(prefixLength);
- return new AffixMatcher(prefix, suffix, flags);
+ appendTo.add(new AffixMatcher(prefix, suffix, flags));
+ if (includeUnpaired && !prefix.isEmpty() && !suffix.isEmpty()) {
+ appendTo.add(new AffixMatcher(prefix, "", flags));
+ appendTo.add(new AffixMatcher("", suffix, flags));
+ }
}
private AffixMatcher(String prefix, String suffix, int flags) {
public void postProcess(ParsedNumber result) {
// Check to see if our affix is the one that was matched. If so, set the flags in the result.
if (prefix.equals(orEmpty(result.prefix)) && suffix.equals(orEmpty(result.suffix))) {
+ // Fill in the result prefix and suffix with non-null values (empty string).
+ // Used by strict mode to determine whether an entire affix pair was matched.
+ result.prefix = prefix;
+ result.suffix = suffix;
result.flags |= flags;
}
}
// License & terms of use: http://www.unicode.org/copyright.html#License
package com.ibm.icu.impl.number.parse;
-import java.math.RoundingMode;
-
import com.ibm.icu.impl.number.DecimalQuantity_DualStorageBCD;
-import com.ibm.icu.impl.number.RoundingUtils;
import com.ibm.icu.lang.UCharacter;
import com.ibm.icu.text.DecimalFormatSymbols;
import com.ibm.icu.text.UnicodeSet;
public static DecimalMatcher getInstance(DecimalFormatSymbols symbols) {
String groupingSeparator = symbols.getGroupingSeparatorString();
- UnicodeSet groupingSet = UNISET_COMMA_LIKE.contains(groupingSeparator) ? UNISET_COMMA_LIKE.cloneAsThawed().addAll(UNISET_OTHER_GROUPING_SEPARATORS).freeze()
- : UNISET_PERIOD_LIKE.contains(groupingSeparator) ? UNISET_PERIOD_LIKE.cloneAsThawed().addAll(UNISET_OTHER_GROUPING_SEPARATORS).freeze()
+ UnicodeSet groupingSet = UNISET_COMMA_LIKE.contains(groupingSeparator)
+ ? UNISET_COMMA_LIKE.cloneAsThawed().addAll(UNISET_OTHER_GROUPING_SEPARATORS).freeze()
+ : UNISET_PERIOD_LIKE.contains(groupingSeparator)
+ ? UNISET_PERIOD_LIKE.cloneAsThawed().addAll(UNISET_OTHER_GROUPING_SEPARATORS).freeze()
: UNISET_OTHER_GROUPING_SEPARATORS.contains(groupingSeparator)
? UNISET_OTHER_GROUPING_SEPARATORS
: new UnicodeSet().addAll(groupingSeparator).freeze();
}
public static DecimalMatcher getExponentInstance(DecimalFormatSymbols symbols) {
- return new DecimalMatcher(symbols
- .getDigitStrings(), new UnicodeSet("[,]").freeze(), new UnicodeSet("[.]").freeze(), true);
+ return new DecimalMatcher(symbols.getDigitStrings(),
+ new UnicodeSet("[,]").freeze(),
+ new UnicodeSet("[.]").freeze(),
+ true);
}
private final String[] digitStrings;
private final UnicodeSet separatorSet;
public boolean requireGroupingMatch = false;
public boolean groupingEnabled = true;
- private final int grouping1 = 3;
- private final int grouping2 = 3;
+ public int grouping1 = 3;
+ public int grouping2 = 3;
+ public boolean integerOnly = false;
private final boolean isScientific;
private DecimalMatcher(
return false;
}
+ int initialOffset = segment.getOffset();
int currGroup = 0;
int separator = -1;
int lastSeparatorOffset = segment.getOffset();
- int scientificAdjustment = 0;
+ int exponent = 0;
boolean hasPartialPrefix = false;
boolean seenBothSeparators = false;
while (segment.length() > 0) {
// If found, save it in the DecimalQuantity or scientific adjustment.
if (digit >= 0) {
if (isScientific) {
- scientificAdjustment = digit + scientificAdjustment * 10;
+ exponent = digit + exponent * 10;
} else {
if (result.quantity == null) {
result.quantity = new DecimalQuantity_DualStorageBCD();
}
if (isScientific) {
- result.quantity.adjustMagnitude(scientificAdjustment);
+ result.quantity.adjustMagnitude(exponent);
} else if (seenBothSeparators || (separator != -1 && decimalUniSet.contains(separator))) {
+ // The final separator was a decimal separator.
+ result.quantity.adjustMagnitude(-currGroup);
+ if (integerOnly) {
+ result.quantity.truncate();
+ segment.setOffset(lastSeparatorOffset);
+ }
+ } else if (separator != -1 && !groupingEnabled) {
+ // The final separator was a grouping separator, but we aren't accepting grouping.
+ // Reset the offset to immediately before that grouping separator.
result.quantity.adjustMagnitude(-currGroup);
- } else if (separator != -1
- && ((requireGroupingMatch && groupingUniSet.contains(separator) && currGroup != grouping1)
- || !groupingEnabled)) {
+ result.quantity.truncate();
+ segment.setOffset(lastSeparatorOffset);
+ } else if (separator != -1 && requireGroupingMatch && groupingUniSet.contains(separator)
+ && currGroup != grouping1) {
+ // The final separator was a grouping separator, and we have a mismatched grouping size.
+ // Reset the offset to the beginning of the number.
+ // TODO
result.quantity.adjustMagnitude(-currGroup);
- result.quantity.roundToMagnitude(0, RoundingUtils.mathContextUnlimited(RoundingMode.FLOOR));
+ result.quantity.truncate();
segment.setOffset(lastSeparatorOffset);
+// result.quantity = null;
+// segment.setOffset(initialOffset);
}
return segment.length() == 0 || hasPartialPrefix || segment.isLeadingSurrogate();
public class MinusSignMatcher extends SymbolMatcher {
public MinusSignMatcher() {
+ // FIXME
super("-", new UnicodeSet("[-_]"));
}
// Temporary frontend for testing.
NumberParserImpl parser = new NumberParserImpl();
- ULocale locale = ULocale.ENGLISH;
+ ULocale locale = new ULocale("en_IN");
DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(locale);
MutablePatternModifier mod = new MutablePatternModifier(false);
if (provider.containsSymbolType(AffixUtils.TYPE_PERMILLE)) {
flags |= ParsedNumber.FLAG_PERMILLE;
}
- AffixMatcher.generateFromPatternModifier(mod, flags, parser);
+ AffixMatcher.generateFromPatternModifier(mod, flags, true, parser);
+ parser.addMatcher(WhitespaceMatcher.getInstance());
DecimalMatcher decimalMatcher = DecimalMatcher.getInstance(symbols);
decimalMatcher.requireGroupingMatch = strictGrouping;
+ decimalMatcher.grouping1 = 3;
+ decimalMatcher.grouping2 = 2;
parser.addMatcher(decimalMatcher);
- parser.addMatcher(WhitespaceMatcher.getInstance());
parser.addMatcher(new MinusSignMatcher());
parser.addMatcher(new ScientificMatcher(symbols));
parser.addMatcher(new CurrencyMatcher(locale));
+ parser.addMatcher(new RequirementsMatcher());
parser.freeze();
return parser;
public static Number parseStatic(String input,
ParsePosition ppos,
DecimalFormatProperties properties,
- DecimalFormatSymbols symbols) {
- NumberParserImpl parser = createParserFromProperties(properties, symbols);
+ DecimalFormatSymbols symbols,
+ boolean parseCurrency) {
+ NumberParserImpl parser = createParserFromProperties(properties, symbols, parseCurrency);
ParsedNumber result = new ParsedNumber();
parser.parse(input, true, result);
ppos.setIndex(result.charsConsumed);
- return result.getDouble();
+ if (result.charsConsumed > 0) {
+ return result.getDouble();
+ } else {
+ return null;
+ }
}
public static NumberParserImpl createParserFromProperties(
DecimalFormatProperties properties,
- DecimalFormatSymbols symbols) {
+ DecimalFormatSymbols symbols,
+ boolean parseCurrency) {
NumberParserImpl parser = new NumberParserImpl();
ULocale locale = symbols.getULocale();
Currency currency = CustomSymbolCurrency.resolve(properties.getCurrency(), locale, symbols);
+ boolean isStrict = properties.getParseMode() == ParseMode.STRICT;
//////////////////////
/// AFFIX MATCHERS ///
flags |= ParsedNumber.FLAG_PERMILLE;
}
- AffixMatcher.generateFromPatternModifier(mod, flags, parser);
+ AffixMatcher.generateFromPatternModifier(mod, flags, !isStrict, parser);
///////////////////////////////
/// OTHER STANDARD MATCHERS ///
///////////////////////////////
+ if (!isStrict) {
+ parser.addMatcher(WhitespaceMatcher.getInstance());
+ parser.addMatcher(new PlusSignMatcher());
+ }
+ parser.addMatcher(new MinusSignMatcher());
DecimalMatcher decimalMatcher = DecimalMatcher.getInstance(symbols);
decimalMatcher.groupingEnabled = properties.getGroupingSize() > 0;
- decimalMatcher.requireGroupingMatch = properties.getParseMode() == ParseMode.STRICT;
+ decimalMatcher.requireGroupingMatch = isStrict;
+ decimalMatcher.grouping1 = properties.getGroupingSize();
+ decimalMatcher.grouping2 = properties.getSecondaryGroupingSize();
+ decimalMatcher.integerOnly = properties.getParseIntegerOnly();
parser.addMatcher(decimalMatcher);
- parser.addMatcher(WhitespaceMatcher.getInstance());
- parser.addMatcher(new MinusSignMatcher());
parser.addMatcher(new ScientificMatcher(symbols));
+ parser.addMatcher(new RequirementsMatcher());
+ if (isStrict) {
+ parser.addMatcher(new RequireAffixMatcher());
+ }
+ if (isStrict && properties.getMinimumExponentDigits() > 0) {
+ parser.addMatcher(new RequireExponentMatcher());
+ }
////////////////////////
/// CURRENCY MATCHER ///
////////////////////////
- parser.addMatcher(new CurrencyMatcher(locale));
+ if (parseCurrency) {
+ parser.addMatcher(new CurrencyMatcher(locale));
+ }
parser.freeze();
return parser;
*/
public class ParsedNumber {
- public DecimalQuantity_DualStorageBCD quantity = null;
+ public DecimalQuantity_DualStorageBCD quantity;
/**
* The number of chars accepted during parsing. This is NOT necessarily the same as the StringSegment offset; "weak"
* chars, like whitespace, change the offset, but the charsConsumed is not touched until a "strong" char is
* encountered.
*/
- public int charsConsumed = 0;
+ public int charsConsumed;
/**
* Boolean flags (see constants below).
*/
- public int flags = 0;
+ public int flags;
/**
* The prefix string that got consumed.
*/
- public String prefix = null;
+ public String prefix;
/**
* The suffix string that got consumed.
*/
- public String suffix = null;
+ public String suffix;
/**
* The currency that got consumed.
*/
- public String currencyCode = null;
+ public String currencyCode;
public static final int FLAG_NEGATIVE = 0x0001;
public static final int FLAG_PERCENT = 0x0002;
public static final int FLAG_PERMILLE = 0x0004;
+ public static final int FLAG_HAS_EXPONENT = 0x0008;
/** A Comparator that favors ParsedNumbers with the most chars consumed. */
public static final Comparator<ParsedNumber> COMPARATOR = new Comparator<ParsedNumber>() {
}
};
+ public ParsedNumber() {
+ clear();
+ }
+
/**
- * @param other
+ * Clears the data from this ParsedNumber, in effect failing the current parse.
*/
+ public void clear() {
+ quantity = null;
+ charsConsumed = 0;
+ flags = 0;
+ prefix = null;
+ suffix = null;
+ currencyCode = null;
+ }
+
public void copyFrom(ParsedNumber other) {
- quantity = other.quantity;
+ quantity = other.quantity == null ? null : (DecimalQuantity_DualStorageBCD) other.quantity.createCopy();
charsConsumed = other.charsConsumed;
flags = other.flags;
prefix = other.prefix;
--- /dev/null
+// © 2017 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html#License
+package com.ibm.icu.impl.number.parse;
+
+import com.ibm.icu.text.UnicodeSet;
+
+/**
+ * @author sffc
+ *
+ */
+public class PlusSignMatcher extends SymbolMatcher {
+
+ public PlusSignMatcher() {
+ // FIXME
+ super("+", new UnicodeSet("[+]"));
+ }
+
+ @Override
+ protected boolean isDisabled(ParsedNumber result) {
+ return false;
+ }
+
+ @Override
+ protected void accept(ParsedNumber result) {
+ // No-op
+ }
+
+ @Override
+ public String toString() {
+ return "<PlusSignMatcher>";
+ }
+
+}
--- /dev/null
+// © 2017 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html#License
+package com.ibm.icu.impl.number.parse;
+
+/**
+ * @author sffc
+ *
+ */
+public class RequireAffixMatcher implements NumberParseMatcher {
+
+ @Override
+ public boolean match(StringSegment segment, ParsedNumber result) {
+ return false;
+ }
+
+ @Override
+ public void postProcess(ParsedNumber result) {
+ if ((result.prefix == null) != (result.suffix == null)) {
+ // We saw a prefix or a suffix but not both. Fail the parse.
+ result.clear();
+ }
+ }
+
+}
* @author sffc
*
*/
-public class StrictMatcher implements NumberParseMatcher {
+public class RequireExponentMatcher implements NumberParseMatcher {
@Override
public boolean match(StringSegment segment, ParsedNumber result) {
@Override
public void postProcess(ParsedNumber result) {
- if (result.prefix == null && result.suffix == null) {
- // Do something?
+ if (0 == (result.flags & ParsedNumber.FLAG_HAS_EXPONENT)) {
+ result.clear();
}
}
--- /dev/null
+// © 2017 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html#License
+package com.ibm.icu.impl.number.parse;
+
+/**
+ * @author sffc
+ *
+ */
+public class RequirementsMatcher implements NumberParseMatcher {
+
+ @Override
+ public boolean match(StringSegment segment, ParsedNumber result) {
+ return false;
+ }
+
+ @Override
+ public void postProcess(ParsedNumber result) {
+ // Require that a number is matched.
+ if (result.quantity == null) {
+ result.clear();
+ }
+ }
+
+}
// Full exponent separator match; allow a sign, and then try to match digits.
segment.adjustOffset(overlap1);
int overlap2 = segment.getCommonPrefixLength(minusSignString);
- boolean sign = false;
+ boolean minusSign = false;
if (overlap2 == minusSignString.length()) {
- sign = true;
+ minusSign = true;
segment.adjustOffset(overlap2);
} else if (overlap2 == segment.length()) {
// Partial sign match
int digitsOffset = segment.getOffset();
int oldMagnitude = result.quantity.getMagnitude();
boolean digitsReturnValue = exponentMatcher.match(segment, result);
- if (result.quantity.getMagnitude() != oldMagnitude && sign) {
- result.quantity.adjustMagnitude(2*(oldMagnitude - result.quantity.getMagnitude()));
- }
- if (segment.getOffset() == digitsOffset) {
- // No digits were matched; un-match the exponent separator.
+ if (segment.getOffset() != digitsOffset) {
+ // At least one exponent digit was matched.
+ result.flags |= ParsedNumber.FLAG_HAS_EXPONENT;
+ if (minusSign) {
+ // Switch the magnitude adjustment from positive to negative. Extracting the exponent from the
+ // change in the quantity's magnitude feels a bit like a hack; better would be for the
+ // DecimalMatcher to somehow return the exponent directly.
+ int exponent = result.quantity.getMagnitude() - oldMagnitude;
+ result.quantity.adjustMagnitude(-2 * exponent);
+ }
+ } else {
+ // No exponent digits were matched; un-match the exponent separator.
segment.adjustOffset(-overlap1);
}
return digitsReturnValue;
(5,347.25) -5347.25
// J requires prefix and suffix for lenient parsing, but C doesn't
5,347.25 5347.25 JK
-(5,347.25 -5347.25 JP
+(5,347.25 -5347.25 J
// S is successful at parsing this as -5347.25 in lenient mode
-5,347.25 -5347.25 CJK
+3.52E4 35200
(34,,25 E-1) -342.5 CJK
// Spaces are not allowed after exponent symbol
// C parses up to the E but J bails
-// P does not make the number negative
-(34 25E -1) -3425 JKP
+(34 25E -1) -3425 JK
+3.52EE4 3.52
+1,234,567.8901 1234567.8901
+1,23,4567.8901 1234567.8901
( 19 45 ) -1945 JK
(,,19,45) -1945
// C parses to the space, but J bails
-// P makes the number positive
-(,,19 45) -19 JP
+(,,19 45) -19 J
// J bails b/c comma different separator than space. C doesn't treat leading spaces
// as a separator.
-( 19,45) -1945 JKP
+( 19,45) -1945 JK
// J bails. Doesn't allow trailing separators when there is prefix and suffix.
(,,19,45,) -1945 J
// J bails on next 4 because J doesn't allow letters inside prefix and suffix.
// C will parse up to the letter.
-(,,19,45,d1) -1945 JP
-(,,19,45d1) -1945 JP
-( 19 45 d1) -1945 JKP
-( 19 45d1) -1945 JKP
+(,,19,45,d1) -1945 J
+(,,19,45d1) -1945 J
+( 19 45 d1) -1945 JK
+( 19 45d1) -1945 JK
// J does allow trailing separator before a decimal point
(19,45,.25) -1945.25
// 2nd decimal points are ignored
(65347.25) -65347.25
(65,347.25) -65347.25
// JDK does allow separators in the wrong place and parses as -5347.25
-(53,47.25) fail KP
+(53,47.25) fail K
// strict requires prefix or suffix, except in C
-65,347.25 fail
+65,347.25 fail P
+3.52E4 35200
(34.8E-3) -0.0348
(3425E-1) -342.5
// Strict doesn't allow separators in sci notation.
(63,425) -63425
-// JDK and S allow separators in sci notation and parses as -342.5
-// C passes
-(63,425E-1) fail CKS
+// J does not allow grouping separators in scientific notation.
+(63,425E-1) -6342.5 J
// Both prefix and suffix needed for strict.
// JDK accepts this and parses as -342.5
(3425E-1 fail K
// have no separators at all.
+12,345.67 12345.67
// JDK doesn't require separators to be in the right place.
-+1,23,4567.8901 fail K
-+1,234,567.8901 fail K
-+1234,567.8901 fail K
-+1,234567.8901 fail K
+// P stops after reading an unexpected grouping separator instead of failing.
++1,23,4567.8901 fail KP
++1,234,567.8901 fail KP
++1234,567.8901 fail KP
++1,234567.8901 fail KP
+1234567.8901 1234567.8901
// Minimum grouping is not satisfied below, but that's ok
// because minimum grouping is optional.
actual = NumberParserImpl.parseStatic(tuple.parse,
ppos,
properties,
- DecimalFormatSymbols.getInstance(tuple.locale));
+ DecimalFormatSymbols.getInstance(tuple.locale),
+ false);
} catch (IllegalArgumentException e) {
return "parse exception: " + e.getMessage();
}
private static final MathContext MATH_CONTEXT_HALF_EVEN =
new MathContext(0, RoundingMode.HALF_EVEN);
private static final MathContext MATH_CONTEXT_CEILING = new MathContext(0, RoundingMode.CEILING);
+ private static final MathContext MATH_CONTEXT_FLOOR = new MathContext(0, RoundingMode.FLOOR);
private static final MathContext MATH_CONTEXT_PRECISION =
new MathContext(3, RoundingMode.HALF_UP);
q0.roundToMagnitude(-1, MATH_CONTEXT_PRECISION);
q1.roundToMagnitude(-1, MATH_CONTEXT_PRECISION);
testDecimalQuantityBehavior(q0, q1);
+
+ q0 = rq0.createCopy();
+ q1 = rq1.createCopy();
+ q0.roundToMagnitude(0, MATH_CONTEXT_FLOOR);
+ q1.truncate();
+ testDecimalQuantityBehavior(q0, q1);
+
+ q0 = rq0.createCopy();
+ q1 = rq1.createCopy();
+ q0.truncate();
+ q1.roundToMagnitude(0, MATH_CONTEXT_FLOOR);
+ testDecimalQuantityBehavior(q0, q1);
}
private static void testDecimalQuantityRoundingInterval(DecimalQuantity rq0, DecimalQuantity rq1) {
{ 3, " 𝟱𝟭𝟰𝟮𝟯", "0", 11, 51423. },
{ 3, "𝟱𝟭𝟰𝟮𝟯 ", "0", 10, 51423. },
{ 7, "𝟱𝟭,𝟰𝟮𝟯", "0", 11, 51423. },
- { 7, "𝟳𝟴,𝟵𝟱𝟭,𝟰𝟮𝟯", "0", 18, 78951423. },
+ { 7, "𝟳,𝟴𝟵,𝟱𝟭,𝟰𝟮𝟯", "0", 19, 78951423. },
+ { 4, "𝟳𝟴,𝟵𝟱𝟭,𝟰𝟮𝟯", "0", 11, 78951. },
{ 7, "𝟳𝟴,𝟵𝟱𝟭.𝟰𝟮𝟯", "0", 18, 78951.423 },
{ 7, "𝟳𝟴,𝟬𝟬𝟬", "0", 11, 78000. },
{ 7, "𝟳𝟴,𝟬𝟬𝟬.𝟬𝟬𝟬", "0", 18, 78000. },
{ 3, "a 𝟱𝟭𝟰𝟮𝟯 b", "a0b", 14, 51423. },
{ 3, "-a 𝟱𝟭𝟰𝟮𝟯 b", "a0b", 15, -51423. },
{ 3, "a -𝟱𝟭𝟰𝟮𝟯 b", "a0b", 15, -51423. },
+ { 3, "𝟱𝟭𝟰𝟮𝟯", "0;(0)", 10, 51423. },
+ { 3, "(𝟱𝟭𝟰𝟮𝟯)", "0;(0)", 12, -51423. },
+ { 3, "𝟱𝟭𝟰𝟮𝟯)", "0;(0)", 11, -51423. },
+ { 3, "(𝟱𝟭𝟰𝟮𝟯", "0;(0)", 11, -51423. },
{ 1, "a40b", "a0'0b'", 3, 40. }, // greedy code path thinks "40" is the number
{ 2, "a40b", "a0'0b'", 4, 4. }, // slow code path find the suffix "0b"
{ 3, "𝟱.𝟭𝟰𝟮E𝟯", "0", 12, 5142. },
// noop
}
+ @Override
+ public void truncate() {
+ roundToMagnitude(0, RoundingUtils.mathContextUnlimited(RoundingMode.FLOOR));
+ }
+
/**
* Multiply the internal number by the specified multiplicand. This method forces the internal
* representation into a BigDecimal. If you are multiplying by a power of 10, use {@link