1fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert// © 2017 and later: Unicode, Inc. and others. 2fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert// License & terms of use: http://www.unicode.org/copyright.html#License 3fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubertpackage com.ibm.icu.number; 4fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 5fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubertimport com.ibm.icu.impl.number.DecimalQuantity; 6fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubertimport com.ibm.icu.impl.number.MicroProps; 7fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubertimport com.ibm.icu.impl.number.MicroPropsGenerator; 8fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubertimport com.ibm.icu.impl.number.Modifier; 9fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubertimport com.ibm.icu.impl.number.MultiplierProducer; 10fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubertimport com.ibm.icu.impl.number.NumberStringBuilder; 11fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubertimport com.ibm.icu.impl.number.RoundingUtils; 12fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubertimport com.ibm.icu.number.NumberFormatter.SignDisplay; 13fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubertimport com.ibm.icu.number.Rounder.SignificantRounderImpl; 14fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubertimport com.ibm.icu.text.DecimalFormatSymbols; 15fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubertimport com.ibm.icu.text.NumberFormat; 16fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 17fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert/** 18fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert * A class that defines the scientific notation style to be used when formatting numbers in NumberFormatter. 19fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert * 20fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert * <p> 21fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert * To create a ScientificNotation, use one of the factory methods in {@link Notation}. 22fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert * 23fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert * @draft ICU 60 24fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert * @provisional This API might change or be removed in a future release. 25fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert * @see NumberFormatter 26fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert */ 27fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubertpublic class ScientificNotation extends Notation implements Cloneable { 28fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 29fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert int engineeringInterval; 30fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert boolean requireMinInt; 31fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert int minExponentDigits; 32fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert SignDisplay exponentSignDisplay; 33fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 34fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert /* package-private */ ScientificNotation(int engineeringInterval, boolean requireMinInt, int minExponentDigits, 35fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert SignDisplay exponentSignDisplay) { 36fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert this.engineeringInterval = engineeringInterval; 37fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert this.requireMinInt = requireMinInt; 38fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert this.minExponentDigits = minExponentDigits; 39fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert this.exponentSignDisplay = exponentSignDisplay; 40fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 41fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 42fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert /** 43fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert * Sets the minimum number of digits to show in the exponent of scientific notation, padding with zeros if 44fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert * necessary. Useful for fixed-width display. 45fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert * 46fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert * <p> 47fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert * For example, with minExponentDigits=2, the number 123 will be printed as "1.23E02" in <em>en-US</em> instead of 48fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert * the default "1.23E2". 49fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert * 50fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert * @param minExponentDigits 51fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert * The minimum number of digits to show in the exponent. 52fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert * @return A ScientificNotation, for chaining. 53fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert * @draft ICU 60 54fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert * @provisional This API might change or be removed in a future release. 55fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert * @see NumberFormatter 56fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert */ 57fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert public ScientificNotation withMinExponentDigits(int minExponentDigits) { 58fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert if (minExponentDigits >= 0 && minExponentDigits < RoundingUtils.MAX_INT_FRAC_SIG) { 59fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert ScientificNotation other = (ScientificNotation) this.clone(); 60fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert other.minExponentDigits = minExponentDigits; 61fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert return other; 62fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } else { 63fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert throw new IllegalArgumentException( 64fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert "Integer digits must be between 0 and " + RoundingUtils.MAX_INT_FRAC_SIG); 65fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 66fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 67fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 68fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert /** 69fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert * Sets whether to show the sign on positive and negative exponents in scientific notation. The default is AUTO, 70fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert * showing the minus sign but not the plus sign. 71fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert * 72fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert * <p> 73fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert * For example, with exponentSignDisplay=ALWAYS, the number 123 will be printed as "1.23E+2" in <em>en-US</em> 74fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert * instead of the default "1.23E2". 75fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert * 76fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert * @param exponentSignDisplay 77fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert * The strategy for displaying the sign in the exponent. 78fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert * @return A ScientificNotation, for chaining. 79fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert * @draft ICU 60 80fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert * @provisional This API might change or be removed in a future release. 81fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert * @see NumberFormatter 82fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert */ 83fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert public ScientificNotation withExponentSignDisplay(SignDisplay exponentSignDisplay) { 84fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert ScientificNotation other = (ScientificNotation) this.clone(); 85fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert other.exponentSignDisplay = exponentSignDisplay; 86fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert return other; 87fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 88fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 89fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert /** 90fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert * @internal 91fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert * @deprecated This API is ICU internal only. 92fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert */ 93fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert @Deprecated 94fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert @Override 95fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert public Object clone() { 96fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert try { 97fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert return super.clone(); 98fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } catch (CloneNotSupportedException e) { 99fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // Should not happen since parent is Object 100fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert throw new AssertionError(e); 101fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 102fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 103fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 104fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert /* package-private */ MicroPropsGenerator withLocaleData(DecimalFormatSymbols symbols, boolean build, 105fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert MicroPropsGenerator parent) { 106fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert return new ScientificHandler(this, symbols, build, parent); 107fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 108fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 109fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // NOTE: The object lifecycle of ScientificModifier and ScientificHandler differ greatly in Java and C++. 110fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // 111fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // During formatting, we need to provide an object with state (the exponent) as the inner modifier. 112fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // 113fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // In Java, where the priority is put on reducing object creations, the unsafe code path re-uses the 114fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // ScientificHandler as a ScientificModifier, and the safe code path pre-computes 25 ScientificModifier 115fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // instances. This scheme reduces the number of object creations by 1 in both safe and unsafe. 116fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // 117fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // In C++, MicroProps provides a pre-allocated ScientificModifier, and ScientificHandler simply populates 118fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // the state (the exponent) into that ScientificModifier. There is no difference between safe and unsafe. 119fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 120fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert private static class ScientificHandler implements MicroPropsGenerator, MultiplierProducer, Modifier { 121fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 122fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert final ScientificNotation notation; 123fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert final DecimalFormatSymbols symbols; 124fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert final ScientificModifier[] precomputedMods; 125fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert final MicroPropsGenerator parent; 126fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert /* unsafe */ int exponent; 127fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 128fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert private ScientificHandler(ScientificNotation notation, DecimalFormatSymbols symbols, boolean safe, 129fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert MicroPropsGenerator parent) { 130fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert this.notation = notation; 131fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert this.symbols = symbols; 132fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert this.parent = parent; 133fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 134fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert if (safe) { 135fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // Pre-build the modifiers for exponents -12 through 12 136fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert precomputedMods = new ScientificModifier[25]; 137fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert for (int i = -12; i <= 12; i++) { 138fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert precomputedMods[i + 12] = new ScientificModifier(i, this); 139fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 140fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } else { 141fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert precomputedMods = null; 142fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 143fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 144fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 145fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert @Override 146fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert public MicroProps processQuantity(DecimalQuantity quantity) { 147fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert MicroProps micros = parent.processQuantity(quantity); 148fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert assert micros.rounding != null; 149fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 150fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // Treat zero as if it had magnitude 0 151fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert int exponent; 152fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert if (quantity.isZero()) { 153fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert if (notation.requireMinInt && micros.rounding instanceof SignificantRounderImpl) { 154fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // Show "00.000E0" on pattern "00.000E0" 155fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert ((SignificantRounderImpl) micros.rounding).apply(quantity, notation.engineeringInterval); 156fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert exponent = 0; 157fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } else { 158fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert micros.rounding.apply(quantity); 159fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert exponent = 0; 160fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 161fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } else { 162fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert exponent = -micros.rounding.chooseMultiplierAndApply(quantity, this); 163fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 164fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 165fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // Add the Modifier for the scientific format. 166fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert if (precomputedMods != null && exponent >= -12 && exponent <= 12) { 167fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // Safe code path A 168fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert micros.modInner = precomputedMods[exponent + 12]; 169fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } else if (precomputedMods != null) { 170fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // Safe code path B 171fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert micros.modInner = new ScientificModifier(exponent, this); 172fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } else { 173fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // Unsafe code path: mutates the object and re-uses it as a Modifier! 174fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert this.exponent = exponent; 175fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert micros.modInner = this; 176fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 177fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 178fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // We already performed rounding. Do not perform it again. 179fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert micros.rounding = Rounder.constructPassThrough(); 180fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 181fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert return micros; 182fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 183fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 184fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert @Override 185fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert public int getMultiplier(int magnitude) { 186fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert int interval = notation.engineeringInterval; 187fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert int digitsShown; 188fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert if (notation.requireMinInt) { 189fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // For patterns like "000.00E0" and ".00E0" 190fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert digitsShown = interval; 191fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } else if (interval <= 1) { 192fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // For patterns like "0.00E0" and "@@@E0" 193fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert digitsShown = 1; 194fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } else { 195fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // For patterns like "##0.00" 196fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert digitsShown = ((magnitude % interval + interval) % interval) + 1; 197fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 198fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert return digitsShown - magnitude - 1; 199fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 200fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 201fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert @Override 202fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert public int getPrefixLength() { 203fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // TODO: Localized exponent separator location. 204fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert return 0; 205fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 206fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 207fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert @Override 208fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert public int getCodePointCount() { 209fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // This method is not used for strong modifiers. 210fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert throw new AssertionError(); 211fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 212fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 213fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert @Override 214fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert public boolean isStrong() { 215fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // Scientific is always strong 216fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert return true; 217fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 218fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 219fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert @Override 220fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert public int apply(NumberStringBuilder output, int leftIndex, int rightIndex) { 221fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert return doApply(exponent, output, rightIndex); 222fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 223fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 224fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert private int doApply(int exponent, NumberStringBuilder output, int rightIndex) { 225fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // FIXME: Localized exponent separator location. 226fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert int i = rightIndex; 227fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // Append the exponent separator and sign 228fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert i += output.insert(i, symbols.getExponentSeparator(), NumberFormat.Field.EXPONENT_SYMBOL); 229fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert if (exponent < 0 && notation.exponentSignDisplay != SignDisplay.NEVER) { 230fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert i += output.insert(i, symbols.getMinusSignString(), NumberFormat.Field.EXPONENT_SIGN); 231fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } else if (exponent >= 0 && notation.exponentSignDisplay == SignDisplay.ALWAYS) { 232fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert i += output.insert(i, symbols.getPlusSignString(), NumberFormat.Field.EXPONENT_SIGN); 233fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 234fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // Append the exponent digits (using a simple inline algorithm) 235fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert int disp = Math.abs(exponent); 236fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert for (int j = 0; j < notation.minExponentDigits || disp > 0; j++, disp /= 10) { 237fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert int d = disp % 10; 238fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert String digitString = symbols.getDigitStringsLocal()[d]; 239fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert i += output.insert(i - j, digitString, NumberFormat.Field.EXPONENT); 240fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 241fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert return i - rightIndex; 242fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 243fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 244fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 245fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert private static class ScientificModifier implements Modifier { 246fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert final int exponent; 247fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert final ScientificHandler handler; 248fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 249fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert ScientificModifier(int exponent, ScientificHandler handler) { 250fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert this.exponent = exponent; 251fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert this.handler = handler; 252fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 253fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 254fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert @Override 255fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert public int apply(NumberStringBuilder output, int leftIndex, int rightIndex) { 256fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert return handler.doApply(exponent, output, rightIndex); 257fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 258fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 259fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert @Override 260fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert public int getPrefixLength() { 261fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // TODO: Localized exponent separator location. 262fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert return 0; 263fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 264fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 265fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert @Override 266fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert public int getCodePointCount() { 267fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // This method is not used for strong modifiers. 268fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert throw new AssertionError(); 269fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 270fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert 271fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert @Override 272fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert public boolean isStrong() { 273fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert // Scientific is always strong 274fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert return true; 275fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 276fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert } 277fe77e7203e518f62b5bd8e8c603bca361e9cf47bFredrik Roubert}