summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorHans Boehm <hboehm@google.com>2015-05-30 13:20:35 -0700
committerHans Boehm <hboehm@google.com>2015-06-08 18:02:25 -0700
commita0e45f306463394d9eeeb887b42ae18c72d69136 (patch)
tree8c84c7c668b98046bdf1c37d9c303ad29c328639 /src
parent694406b52e3bafa9da4396de836e6214e3a9d799 (diff)
downloadandroid_packages_apps_ExactCalculator-a0e45f306463394d9eeeb887b42ae18c72d69136.tar.gz
android_packages_apps_ExactCalculator-a0e45f306463394d9eeeb887b42ae18c72d69136.tar.bz2
android_packages_apps_ExactCalculator-a0e45f306463394d9eeeb887b42ae18c72d69136.zip
Consistently avoid displaying trailing zeroes
Bug: 21405924 Bug: 21529236 Bug: 21534231 This limits the display of trailing zeroes to the case in which they avoid the need for scientic notation, and to the case of results we did not identify as rational. This means that you can use scrolling as an indicator of whether there may be more digits. The old code exhibited some misbehavior around this, the most serious of which was probably the second bug listed above. This now uses scientific notation more aggressively for small numbers (b/21534231). This patch unfortunately needs to deal with many odd corner cases to make sure that we stop scrolling at just the right point, before the first trailing zero appears, even if there are exponents involved. I tested as many corner cases as I could think of. And the testing exposed other preexisting bugs. I do not know of a good way to avoid this without reverting to the old scroll-through-trailing-zeroes behavior. This significantly changes the behavior on e.g. 10^30 (Previously allowed scrolling to the decimal point, now is unscrollable.) 10^-20 (Weird initial display with trailing zeroes; which could not be reproduced after scrolling.) It turns out that formatResult() scientific notation formatting could accidentally extend the input result by 1 or 2 characters. Based on my testing, the one character case was actually a feature: Since there was a decimal point in the result the extra ellipsis space seems to always give us plenty of room. The two character case whoever sometimes resulted in wrapping, and is fixed here. The one character case is now official. Ideally we should check that we actually have enough space; currently I just assume a single additional character. Disallow scrolling left of the default position. This seems more consistent with TextView scrolling and eliminates some crufty code. Fixed an off-by-one error in getPreferredPrec, which resulted in positive results that were one character too short. Change-Id: I13657377d098055def99e7a173f71f40d361fe3c
Diffstat (limited to 'src')
-rw-r--r--src/com/android/calculator2/Calculator.java5
-rw-r--r--src/com/android/calculator2/CalculatorResult.java217
-rw-r--r--src/com/android/calculator2/Evaluator.java87
3 files changed, 229 insertions, 80 deletions
diff --git a/src/com/android/calculator2/Calculator.java b/src/com/android/calculator2/Calculator.java
index b2cf477..dddbad8 100644
--- a/src/com/android/calculator2/Calculator.java
+++ b/src/com/android/calculator2/Calculator.java
@@ -535,11 +535,12 @@ public class Calculator extends Activity
}
// Initial evaluation completed successfully. Initiate display.
- public void onEvaluate(int initDisplayPrec, int leastDigPos, String truncatedWholeNumber) {
+ public void onEvaluate(int initDisplayPrec, int msd, int leastDigPos,
+ String truncatedWholeNumber) {
// Invalidate any options that may depend on the current result.
invalidateOptionsMenu();
- mResultText.displayResult(initDisplayPrec, leastDigPos, truncatedWholeNumber);
+ mResultText.displayResult(initDisplayPrec, msd, leastDigPos, truncatedWholeNumber);
if (mCurrentState != CalculatorState.INPUT) { // in EVALUATE or INIT state
onResult(mCurrentState != CalculatorState.INIT);
}
diff --git a/src/com/android/calculator2/CalculatorResult.java b/src/com/android/calculator2/CalculatorResult.java
index 5b4fb86..7752525 100644
--- a/src/com/android/calculator2/CalculatorResult.java
+++ b/src/com/android/calculator2/CalculatorResult.java
@@ -65,10 +65,13 @@ public class CalculatorResult extends AlignedTextView {
private int mMinPos; // Minimum position before all digits disappear off the right. Pixels.
private int mMaxPos; // Maximum position before we start displaying the infinite
// sequence of trailing zeroes on the right. Pixels.
+ private int mMaxCharPos; // The same, but in characters.
+ private int mLsd; // Position of least-significant digit in result
+ // (1 = tenths, -1 = tens), or Integer.MAX_VALUE.
private final Object mWidthLock = new Object();
// Protects the next two fields.
private int mWidthConstraint = -1;
- // Our total width in pixels.
+ // Our total width in pixels minus space for ellipsis.
private float mCharWidth = 1;
// Maximum character width. For now we pretend that all characters
// have this width.
@@ -77,6 +80,15 @@ public class CalculatorResult extends AlignedTextView {
// is not noticeable.
private static final int MAX_WIDTH = 100;
// Maximum number of digits displayed
+ private static final int MAX_LEADING_ZEROES = 6;
+ // Maximum number of leading zeroes after decimal point before we
+ // switch to scientific notation with negative exponent.
+ private static final int MAX_TRAILING_ZEROES = 6;
+ // Maximum number of trailing zeroes before the decimal point before
+ // we switch to scientific notation with positive exponent.
+ private static final int SCI_NOTATION_EXTRA = 1;
+ // Extra digits for standard scientific notation. In this case we
+ // have a deecimal point and no ellipsis.
private ActionMode mActionMode;
private final ForegroundColorSpan mExponentColorSpan;
@@ -164,47 +176,123 @@ public class CalculatorResult extends AlignedTextView {
}
}
- // Given that the last non-zero digit is at pos, compute the precision we have to ask
- // ask for to actually get the digit at pos displayed. This is not an identity
- // function, since we may need to drop digits to the right to make room for the exponent.
- private int addExpSpace(int lastDigit) {
- if (lastDigit < getMaxChars() - 1) {
- // The decimal point will be in view when displaying the rightmost digit.
- // no exponent needed.
- // TODO: This will change if we stop scrolling to the left of the decimal
- // point, which might be desirable in the traditional scientific notation case.
- return lastDigit;
- }
- // When the last digit is displayed, the exponent will look like "e-<lastDigit>".
- // The length of that string is the extra precision we need.
- return lastDigit + (int)Math.ceil(Math.log10((double)lastDigit)) + 2;
+ // Return the length of the exponent representation for the given exponent, in
+ // characters.
+ private final int expLen(int exp) {
+ if (exp == 0) return 0;
+ return (int)Math.ceil(Math.log10(Math.abs((double)exp))) + (exp >= 0 ? 1 : 2);
+ }
+
+ /**
+ * Initiate display of a new result.
+ * The parameters specify various properties of the result.
+ * @param initPrec Initial display precision computed by evaluator. (1 = tenths digit)
+ * @param msd Position of most significant digit. Offset from left of string.
+ Evaluator.INVALID_MSD if unknown.
+ * @param leastDigPos Position of least significant digit (1 = tenths digit)
+ * or Integer.MAX_VALUE.
+ * @param truncatedWholePart Result up to but not including decimal point.
+ Currently we only use the length.
+ */
+ void displayResult(int initPrec, int msd, int leastDigPos, String truncatedWholePart) {
+ initPositions(initPrec, msd, leastDigPos, truncatedWholePart);
+ redisplay();
}
- // Display a new result, given initial displayed precision, position of the rightmost
- // nonzero digit (or Integer.MAX_VALUE if non-terminating), and the string representing
- // the whole part of the number to be displayed.
- // We pass the string, instead of just the length, so we have one less place to fix in case
- // we ever decide to fully handle a variable width font.
- void displayResult(int initPrec, int leastDigPos, String truncatedWholePart) {
+ /**
+ * Set up scroll bounds and determine whether the result is scrollable, based on the
+ * supplied information about the result.
+ * This is unfortunately complicated because we need to predict whether trailing digits
+ * will eventually be replaced by an exponent.
+ * Just appending the exponent during formatting would be simpler, but would produce
+ * jumpier results during transitions.
+ */
+ private void initPositions(int initPrec, int msd, int leastDigPos, String truncatedWholePart) {
+ float charWidth;
+ int maxChars = getMaxChars();
mLastPos = INVALID;
+ mLsd = leastDigPos;
synchronized(mWidthLock) {
- mCurrentPos = (int) Math.ceil(initPrec * mCharWidth);
+ charWidth = mCharWidth;
+ }
+ mCurrentPos = mMinPos = (int) Math.round(initPrec * charWidth);
+ // Prevent scrolling past initial position, which is calculated to show leading digits.
+ if (msd == Evaluator.INVALID_MSD) {
+ // Possible zero value
+ if (leastDigPos == Integer.MIN_VALUE) {
+ // Definite zero value.
+ mMaxPos = mMinPos;
+ mMaxCharPos = (int) Math.round(mMaxPos/charWidth);
+ mScrollable = false;
+ } else {
+ // May be very small nonzero value. Allow user to find out.
+ mMaxPos = mMaxCharPos = MAX_RIGHT_SCROLL;
+ mScrollable = true;
+ }
+ return;
}
- // Should logically be
+ int wholeLen = truncatedWholePart.length();
+ int negative = truncatedWholePart.charAt(0) == '-' ? 1 : 0;
+ boolean adjustedForExp = false; // Adjusted for normal exponent.
+ if (msd > wholeLen && msd <= wholeLen + 3) {
+ // Avoid tiny negative exponent; pretend msd is just to the right of decimal point.
+ msd = wholeLen - 1;
+ }
+ int minCharPos = msd - negative - wholeLen;
+ // Position of leftmost significant digit relative to dec. point.
+ // Usually negative.
+ mMaxCharPos = MAX_RIGHT_SCROLL; // How far does it make sense to scroll right?
+ // If msd is left of decimal point should logically be
// mMinPos = - (int) Math.ceil(getPaint().measureText(truncatedWholePart)), but
- // we eventually transalate to a character position by dividing by mCharWidth.
+ // we eventually translate to a character position by dividing by mCharWidth.
// To avoid rounding issues, we use the analogous computation here.
- mMinPos = - (int) Math.ceil(truncatedWholePart.length() * mCharWidth);
+ if (minCharPos > -1 && minCharPos < MAX_LEADING_ZEROES + 2) {
+ // Small number of leading zeroes, avoid scientific notation.
+ minCharPos = -1;
+ }
if (leastDigPos < MAX_RIGHT_SCROLL) {
- mMaxPos = Math.min((int) Math.ceil(addExpSpace(leastDigPos) * mCharWidth),
- MAX_RIGHT_SCROLL);
+ mMaxCharPos = leastDigPos;
+ if (mMaxCharPos < -1 && mMaxCharPos > -(MAX_TRAILING_ZEROES + 2)) {
+ mMaxCharPos = -1;
+ }
+ // leastDigPos is positive or negative, never 0.
+ if (mMaxCharPos < -1) {
+ // Number entirely to left of decimal point.
+ // We'll need a positive exponent or displayed zeros to display entire number.
+ mMaxCharPos = Math.min(-1, mMaxCharPos + expLen(-minCharPos - 1));
+ if (mMaxCharPos >= -1) {
+ // Unlikely; huge exponent.
+ mMaxCharPos = -1;
+ } else {
+ adjustedForExp = true;
+ }
+ } else if (minCharPos > -1 || mMaxCharPos >= maxChars) {
+ // Number either entirely to the right of decimal point, or decimal point not
+ // visible when scrolled to the right.
+ // We will need an exponent when looking at the rightmost digit.
+ // Allow additional scrolling to make room.
+ mMaxCharPos += expLen(-(minCharPos + 1));
+ adjustedForExp = true;
+ // Assumed an exponent for standard scientific notation for now.
+ // Adjusted below if necessary.
+ }
+ mScrollable = (mMaxCharPos - minCharPos + negative >= maxChars);
+ if (mScrollable) {
+ if (adjustedForExp) {
+ // We may need a slightly larger negative exponent while scrolling.
+ mMaxCharPos += expLen(-leastDigPos) - expLen(-(minCharPos + 1));
+ }
+ }
+ mMaxPos = Math.min((int) Math.round(mMaxCharPos * charWidth), MAX_RIGHT_SCROLL);
+ if (!mScrollable) {
+ // Position the number consistently with our assumptions to make sure it
+ // actually fits.
+ mCurrentPos = mMaxPos;
+ }
} else {
- mMaxPos = MAX_RIGHT_SCROLL;
+ mMaxPos = mMaxCharPos = MAX_RIGHT_SCROLL;
+ mScrollable = true;
}
- mScrollable = (leastDigPos != (initPrec == -1 ? 0 : initPrec));
- // We assume that initPrec allows most significant digit to be displayed.
- // If there is nothing to the right of initPrec, there is no point in scrolling.
- redisplay();
}
void displayError(int resourceId) {
@@ -215,9 +303,27 @@ public class CalculatorResult extends AlignedTextView {
private final int MAX_COPY_SIZE = 1000000;
+ /*
+ * Return the most significant digit position in the given string or Evaluator.INVALID_MSD.
+ * Unlike Evaluator.getMsdPos, we treat a final 1 as significant.
+ */
+ public static int getNaiveMsdPos(String s) {
+ int len = s.length();
+ int nonzeroPos = -1;
+ for (int i = 0; i < len; ++i) {
+ char c = s.charAt(i);
+ if (c != '-' && c != '.' && c != '0') {
+ return i;
+ }
+ }
+ return Evaluator.INVALID_MSD;
+ }
+
// Format a result returned by Evaluator.getString() into a single line containing ellipses
- // (if appropriate) and an exponent (if appropriate). digs is the value that was passed to
+ // (if appropriate) and an exponent (if appropriate). prec is the value that was passed to
// getString and thus identifies the significance of the rightmost digit.
+ // A value of 1 means the rightmost digits corresponds to tenths.
+ // maxDigs is the maximum number of characters in the result.
// We add two distinct kinds of exponents:
// 1) If the final result contains the leading digit we use standard scientific notation.
// 2) If not, we add an exponent corresponding to an interpretation of the final result as
@@ -227,37 +333,41 @@ public class CalculatorResult extends AlignedTextView {
// would have been in had we not done so.
// This minimizes jumps as a result of scrolling. Result is NOT internationalized,
// uses "e" for exponent.
- public String formatResult(String res, int digs,
+ public String formatResult(String res, int prec,
int maxDigs, boolean truncated,
boolean negative) {
+ int msd; // Position of most significant digit in res or indication its outside res.
+ int minusSpace = negative ? 1 : 0;
if (truncated) {
res = KeyMaps.ELLIPSIS + res.substring(1, res.length());
+ msd = -1;
+ } else {
+ msd = getNaiveMsdPos(res); // INVALID_MSD is OK and is treated as large.
}
int decIndex = res.indexOf('.');
int resLen = res.length();
- if (decIndex == -1 && digs != -1) {
- // No decimal point displayed, and it's not just to the right of the last digit.
+ if ((decIndex == -1 || msd != Evaluator.INVALID_MSD
+ && msd - decIndex > MAX_LEADING_ZEROES + 1) && prec != -1) {
+ // No decimal point displayed, and it's not just to the right of the last digit,
+ // or we should suppress leading zeroes.
// Add an exponent to let the user track which digits are currently displayed.
// This is a bit tricky, since the number of displayed digits affects the displayed
// exponent, which can affect the room we have for mantissa digits. We occasionally
// display one digit too few. This is sometimes unavoidable, but we could
// avoid it in more cases.
- int exp = digs > 0 ? -digs : -digs - 1;
+ int exp = prec > 0 ? -prec : -prec - 1;
// Can be used as TYPE (2) EXPONENT. -1 accounts for decimal point.
- int msd; // Position of most significant digit in res or indication its outside res.
boolean hasPoint = false;
- if (truncated) {
- msd = -1;
- } else {
- msd = Evaluator.getMsdPos(res); // INVALID_MSD is OK
- }
- if (msd < maxDigs - 1 && msd >= 0) {
+ if (msd < maxDigs - 1 && msd >= 0 &&
+ resLen - msd + 1 /* dec. pt. */ + minusSpace <= maxDigs + SCI_NOTATION_EXTRA) {
// TYPE (1) EXPONENT computation and transformation:
// Leading digit is in display window. Use standard calculator scientific notation
// with one digit to the left of the decimal point. Insert decimal point and
// delete leading zeroes.
+ // We try to keep leading digits roughly in position, and never
+ // lengthen the result by more than SCI_NOT_EXTRA.
String fraction = res.substring(msd + 1, resLen);
- res = (negative ? "-" : "") + res.substring(msd, msd+1) + "." + fraction;
+ res = (negative ? "-" : "") + res.substring(msd, msd + 1) + "." + fraction;
exp += resLen - msd - 1;
// Original exp was correct for decimal point at right of fraction.
// Adjust by length of fraction.
@@ -272,7 +382,7 @@ public class CalculatorResult extends AlignedTextView {
// Drop digits even if there is room. Otherwise the scrolling gets jumpy.
if (dropDigits >= resLen - 1) {
dropDigits = Math.max(resLen - 2, 0);
- // Jumpy is better than no mantissa.
+ // Jumpy is better than no mantissa. Probably impossible anyway.
}
if (!hasPoint) {
// Special handling for TYPE(2) EXPONENT:
@@ -286,8 +396,18 @@ public class CalculatorResult extends AlignedTextView {
// ++expDigits; (dead code)
++dropDigits;
++exp;
+ expAsString = Integer.toString(exp);
// This cannot increase the length a second time.
}
+ if (prec - dropDigits > mLsd) {
+ // This can happen if e.g. result = 10^40 + 10^10
+ // It turns out we would otherwise display ...10e9 because
+ // it takes the same amount of space as ...1e10 but shows one more digit.
+ // But we don't want to display a trailing zero, even if it's free.
+ ++dropDigits;
+ ++exp;
+ expAsString = Integer.toString(exp);
+ }
}
res = res.substring(0, resLen - dropDigits);
res = res + "e" + expAsString;
@@ -302,7 +422,8 @@ public class CalculatorResult extends AlignedTextView {
final boolean truncated[] = new boolean[1];
final boolean negative[] = new boolean[1];
final int requested_prec[] = {pos};
- final String raw_res = mEvaluator.getString(requested_prec, maxSize, truncated, negative);
+ final String raw_res = mEvaluator.getString(requested_prec, mMaxCharPos,
+ maxSize, truncated, negative);
return formatResult(raw_res, requested_prec[0], maxSize, truncated[0], negative[0]);
}
@@ -356,7 +477,7 @@ public class CalculatorResult extends AlignedTextView {
int getCurrentCharPos() {
synchronized(mWidthLock) {
- return (int) Math.ceil(mCurrentPos / mCharWidth);
+ return (int) Math.round(mCurrentPos / mCharWidth);
}
}
diff --git a/src/com/android/calculator2/Evaluator.java b/src/com/android/calculator2/Evaluator.java
index 9b9e830..fc07eca 100644
--- a/src/com/android/calculator2/Evaluator.java
+++ b/src/com/android/calculator2/Evaluator.java
@@ -55,10 +55,10 @@
// When we are in danger of not having digits to display in response
// to further scrolling, we initiate a background computation to higher
// precision. If we actually do fall behind, we display placeholder
-// characters, e.g. '?', and schedule a display update when the computation
+// characters, e.g. blanks, and schedule a display update when the computation
// completes.
// The code is designed to ensure that the error in the displayed
-// result (excluding any '?' characters) is always strictly less than 1 in
+// result (excluding any placeholder characters) is always strictly less than 1 in
// the last displayed digit. Typically we actually display a prefix
// of a result that has this property and additionally is computed to
// a significantly higher precision. Thus we almost always round correctly
@@ -373,9 +373,8 @@ class Evaluator {
initCache = res.mVal.toString(prec);
msd = getMsdPos(initCache);
}
- int initDisplayPrec =
- getPreferredPrec(initCache, msd,
- BoundedRational.digitsRequired(res.mRatVal));
+ int lsd = getLsd(res.mRatVal, initCache, initCache.indexOf('.'));
+ int initDisplayPrec = getPreferredPrec(initCache, msd, lsd);
int newPrec = initDisplayPrec + EXTRA_DIGITS;
if (newPrec > prec) {
prec = newPrec;
@@ -422,7 +421,7 @@ class Evaluator {
// checking for change.
int init_prec = result.mInitDisplayPrec;
int msd = getMsdPos(mCache);
- int leastDigPos = BoundedRational.digitsRequired(mRatVal);
+ int leastDigPos = getLsd(mRatVal, mCache, dotPos);
int new_init_prec = getPreferredPrec(mCache, msd, leastDigPos);
if (new_init_prec < init_prec) {
init_prec = new_init_prec;
@@ -431,7 +430,7 @@ class Evaluator {
// happen if they're not. e.g. because
// CalculatorResult.MAX_WIDTH was too small.
}
- mCalculator.onEvaluate(init_prec, leastDigPos, truncatedWholePart);
+ mCalculator.onEvaluate(init_prec, msd, leastDigPos, truncatedWholePart);
}
@Override
protected void onCancelled(InitialResult result) {
@@ -463,38 +462,66 @@ class Evaluator {
mCurrentReevaluator.execute(mCacheDigsReq);
}
- // Retrieve the preferred precision for the currently
- // displayed result, given the number of characters we
- // have room for and the current string approximation for
- // the result.
- // lastDigit is the position of the last digit on the right
- // if there is such a thing, or Integer.MAX_VALUE.
- // May be called in non-UI thread.
+ /**
+ * Return the rightmost nonzero digit position, if any.
+ * @param ratVal Rational value of result or null.
+ * @param cache Current cached decimal string representation of result.
+ * @param decPos Index of decimal point in cache.
+ * @result Position of rightmost nonzero digit relative to decimal point.
+ * Integer.MIN_VALUE if ratVal is zero. Integer.MAX_VALUE if there is no lsd,
+ * or we cannot determine it.
+ */
+ int getLsd(BoundedRational ratVal, String cache, int decPos) {
+ if (ratVal != null && ratVal.signum() == 0) return Integer.MIN_VALUE;
+ int result = BoundedRational.digitsRequired(ratVal);
+ if (result == 0) {
+ int i;
+ for (i = -1; decPos + i > 0 && cache.charAt(decPos + i) == '0'; --i) { }
+ result = i;
+ }
+ return result;
+ }
+
+ /**
+ * Retrieve the preferred precision for the currently displayed result.
+ * May be called from non-UI thread.
+ * @param cache Current approximation as string.
+ * @param msd Position of most significant digit in result. Index in cache.
+ * Can be INVALID_MSD if we haven't found it yet.
+ * @param lastDigit Position of least significant digit (1 = tenths digit)
+ * or Integer.MAX_VALUE.
+ */
int getPreferredPrec(String cache, int msd, int lastDigit) {
int lineLength = mResult.getMaxChars();
int wholeSize = cache.indexOf('.');
+ int negative = cache.charAt(0) == '-' ? 1 : 0;
// Don't display decimal point if result is an integer.
if (lastDigit == 0) lastDigit = -1;
- if (lastDigit != Integer.MAX_VALUE
- && ((wholeSize <= lineLength && lastDigit == 0)
- || wholeSize + lastDigit + 1 /* d.p. */ <= lineLength)) {
- // Prefer to display as integer, without decimal point
- if (lastDigit == 0) return -1;
- return lastDigit;
+ if (lastDigit != Integer.MAX_VALUE) {
+ if (wholeSize <= lineLength && lastDigit <= 0) {
+ // Exact integer. Prefer to display as integer, without decimal point.
+ return -1;
+ }
+ if (lastDigit >= 0 && wholeSize + lastDigit + 1 /* dec.pt. */ <= lineLength) {
+ // Display full exact number wo scientific notation.
+ return lastDigit;
+ }
}
if (msd > wholeSize && msd <= wholeSize + 4) {
- // Display number without scientific notation.
- // Treat leading zero as msd.
+ // Display number without scientific notation. Treat leading zero as msd.
msd = wholeSize - 1;
}
if (msd > wholeSize + MAX_MSD_PREC) {
- // Display a probably but uncertain 0 as "0.000000000",
+ // Display a probable but uncertain 0 as "0.000000000",
// without exponent. That's a judgment call, but less likely
// to confuse naive users. A more informative and confusing
// option would be to use a large negative exponent.
return lineLength - 2;
}
- return msd - wholeSize + lineLength - 2;
+ // Return position corresponding to having msd at left, effectively
+ // presuming scientific notation that preserves the left part of the
+ // result.
+ return msd - wholeSize + lineLength - negative - 1;
}
// Get a short representation of the value represented by
@@ -543,7 +570,6 @@ class Evaluator {
// Unknown, or could change on reevaluation
return INVALID_MSD;
}
-
}
// Return most significant digit position in the cache, if determined,
@@ -614,8 +640,9 @@ class Evaluator {
// getRational() can be used to determine whether the result
// is exact, or whether we dropped trailing digits.
// If the requested prec[0] value is out of range, we update
- // it in place and use the updated value.
- public String getString(int[] prec, int maxDigs,
+ // it in place and use the updated value. But we do not make it
+ // greater than maxPrec.
+ public String getString(int[] prec, int maxPrec, int maxDigs,
boolean[] truncated, boolean[] negative) {
int digs = prec[0];
mLastDigs = digs;
@@ -643,7 +670,7 @@ class Evaluator {
// includes 1 for dec. pt
if (myNegative) --integralDigits;
int minDigs = Math.min(-integralDigits + MIN_DIGS, -1);
- digs = Math.max(digs, minDigs);
+ digs = Math.min(Math.max(digs, minDigs), maxPrec);
prec[0] = digs;
int offset = mCacheDigs - digs; // trailing digits to drop
int deficit = 0; // The number of digits we're short
@@ -715,8 +742,8 @@ class Evaluator {
// Notify immediately, reusing existing result.
int dotPos = mCache.indexOf('.');
String truncatedWholePart = mCache.substring(0, dotPos);
- int leastDigPos = BoundedRational.digitsRequired(mRatVal);
- mCalculator.onEvaluate(mLastDigs, leastDigPos, truncatedWholePart);
+ int leastDigPos = getLsd(mRatVal, mCache, dotPos);
+ mCalculator.onEvaluate(mLastDigs, getMsd(), leastDigPos, truncatedWholePart);
}
}