Real should indicate error in parsing

This commit is contained in:
serso 2016-04-22 21:28:26 +02:00
parent b00e02a693
commit af5bf16182
7 changed files with 56 additions and 43 deletions

View File

@ -1,7 +1,6 @@
package org.solovyev.android.calculator.converter; package org.solovyev.android.calculator.converter;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import jscl.JsclMathEngine; import jscl.JsclMathEngine;
@ -101,17 +100,21 @@ final class Converter {
return 0; return 0;
} }
public static double parse(@NonNull String value) { @NonNull
public static Real parse(@NonNull String value) throws NumberFormatException {
return parse(value, 10); return parse(value, 10);
} }
public static double parse(@NonNull String value, int base) { @NonNull
public static Real parse(@NonNull String value, int base) throws NumberFormatException {
final String groupingSeparator = String.valueOf(JsclMathEngine.getInstance().getGroupingSeparator()); final String groupingSeparator = String.valueOf(JsclMathEngine.getInstance().getGroupingSeparator());
if (!TextUtils.isEmpty(groupingSeparator)) { if (groupingSeparator.length() > 0) {
value = value.replace(groupingSeparator, ""); value = value.replace(groupingSeparator, "");
} }
final Real real = new Real(value, base); final Real real = new Real(value, base);
final long bits = real.toDoubleBits(); if (real.isNan()) {
return Double.longBitsToDouble(bits); throw new NumberFormatException();
}
return real;
} }
} }

View File

@ -21,39 +21,21 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo; import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView; import android.widget.*;
import android.widget.ArrayAdapter; import butterknife.Bind;
import android.widget.EditText; import butterknife.ButterKnife;
import android.widget.ImageButton; import org.solovyev.android.calculator.*;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import org.solovyev.android.calculator.App;
import org.solovyev.android.calculator.AppComponent;
import org.solovyev.android.calculator.AppModule;
import org.solovyev.android.calculator.BaseDialogFragment;
import org.solovyev.android.calculator.Clipboard;
import org.solovyev.android.calculator.Editor;
import org.solovyev.android.calculator.Keyboard;
import org.solovyev.android.calculator.R;
import org.solovyev.android.calculator.keyboard.FloatingKeyboard; import org.solovyev.android.calculator.keyboard.FloatingKeyboard;
import org.solovyev.android.calculator.keyboard.FloatingKeyboardWindow; import org.solovyev.android.calculator.keyboard.FloatingKeyboardWindow;
import org.solovyev.android.calculator.keyboard.FloatingNumberKeyboard; import org.solovyev.android.calculator.keyboard.FloatingNumberKeyboard;
import org.solovyev.android.calculator.math.MathUtils; import org.solovyev.android.calculator.math.MathUtils;
import org.solovyev.android.calculator.view.EditTextCompat; import org.solovyev.android.calculator.view.EditTextCompat;
import java.util.Comparator;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.inject.Inject; import javax.inject.Inject;
import java.util.Comparator;
import butterknife.Bind; import static org.solovyev.android.calculator.UiPreferences.Converter.*;
import butterknife.ButterKnife;
import static org.solovyev.android.calculator.UiPreferences.Converter.lastDimension;
import static org.solovyev.android.calculator.UiPreferences.Converter.lastUnitsFrom;
import static org.solovyev.android.calculator.UiPreferences.Converter.lastUnitsTo;
public class ConverterFragment extends BaseDialogFragment public class ConverterFragment extends BaseDialogFragment
implements AdapterView.OnItemSelectedListener, View.OnFocusChangeListener, TextView.OnEditorActionListener, View.OnClickListener, TextWatcher { implements AdapterView.OnItemSelectedListener, View.OnFocusChangeListener, TextView.OnEditorActionListener, View.OnClickListener, TextWatcher {
@ -332,7 +314,7 @@ public class ConverterFragment extends BaseDialogFragment
final String value = editTextFrom.getText().toString(); final String value = editTextFrom.getText().toString();
if (TextUtils.isEmpty(value)) { if (TextUtils.isEmpty(value)) {
if (validate) { if (validate) {
setError(labelFrom, "Empty"); setError(labelFrom, R.string.cpp_nan);
} }
return; return;
} }
@ -345,7 +327,7 @@ public class ConverterFragment extends BaseDialogFragment
} catch (RuntimeException e) { } catch (RuntimeException e) {
editTextTo.setText(""); editTextTo.setText("");
if (validate) { if (validate) {
setError(labelFrom, e.getLocalizedMessage()); setError(labelFrom, R.string.cpp_nan);
} }
} }
} }

View File

@ -5,7 +5,7 @@ import android.support.annotation.NonNull;
interface Convertible { interface Convertible {
@NonNull @NonNull
String convert(@NonNull Convertible to, @NonNull String value); String convert(@NonNull Convertible to, @NonNull String value) throws NumberFormatException;
@NonNull @NonNull
Named<Convertible> named(@NonNull Context context); Named<Convertible> named(@NonNull Context context);

View File

@ -4,6 +4,7 @@ import android.content.Context;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import jscl.JsclMathEngine; import jscl.JsclMathEngine;
import jscl.NumeralBase; import jscl.NumeralBase;
import midpcalc.Real;
import java.math.BigInteger; import java.math.BigInteger;
@ -20,16 +21,17 @@ public class NumeralBaseConvertible implements Convertible {
@NonNull @NonNull
@Override @Override
public String convert(@NonNull Convertible to, @NonNull String value) { public String convert(@NonNull Convertible to, @NonNull String value) throws NumberFormatException {
final NumeralBase baseTo = ((NumeralBaseConvertible) to).base; final NumeralBase baseTo = ((NumeralBaseConvertible) to).base;
try { final Real real = Converter.parse(value, base.radix);
final BigInteger integer = base.toBigInteger(value); if (real.isIntegral()) {
return mathEngine.format(integer, baseTo); final long l = real.toLong();
} catch (NumberFormatException e) { if (l != Long.MAX_VALUE && l != -Long.MAX_VALUE) {
final double d = Converter.parse(value, base.radix); return mathEngine.format(BigInteger.valueOf(l), baseTo);
return mathEngine.format(d, baseTo);
} }
} }
return mathEngine.format(real.toDouble(), baseTo);
}
@NonNull @NonNull
@Override @Override

View File

@ -34,7 +34,7 @@ final class UnitConvertible implements Convertible {
@NonNull @NonNull
@Override @Override
public String convert(@NonNull Convertible to, @NonNull String value) { public String convert(@NonNull Convertible to, @NonNull String value) {
final double from = Converter.parse(value); final double from = Converter.parse(value).toDouble();
final double converted = unit.getConverterTo(((UnitConvertible) to).unit).convert(from); final double converted = unit.getConverterTo(((UnitConvertible) to).unit).convert(from);
return format(converted); return format(converted);
} }

View File

@ -0,0 +1,18 @@
package org.solovyev.android.calculator.converter;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class ConverterTest {
@Test(expected = NumberFormatException.class)
public void testShouldNotParseInvalidDecNumber() throws Exception {
Converter.parse("1A", 10);
}
@Test
public void testShouldParseValidHexNumber() throws Exception {
assertEquals(26, Converter.parse("1A", 16).toLong());
}
}

View File

@ -771,8 +771,8 @@ public final class Real {
* &nbsp;&nbsp;&nbsp;&nbsp;base-16: <code>"/FFF800C.CCCE e64"</code> * &nbsp;&nbsp;&nbsp;&nbsp;base-16: <code>"/FFF800C.CCCE e64"</code>
* <p/> * <p/>
* <p>The number is parsed until the end of the string or an unknown * <p>The number is parsed until the end of the string or an unknown
* character is encountered, then silently returns even if the whole * character is encountered. Note that in case of latter this Real becomes
* string has not been parsed. Please note that specifying an * NAN. Please note that specifying an
* excessive number of digits in base-10 may in fact decrease the * excessive number of digits in base-10 may in fact decrease the
* accuracy of the result because of the extra multiplications performed. * accuracy of the result because of the extra multiplications performed.
* <p/> * <p/>
@ -2243,6 +2243,10 @@ public final class Real {
return (this.sign == 0) ? (mantissa >>> shift) : -(mantissa >>> shift); return (this.sign == 0) ? (mantissa >>> shift) : -(mantissa >>> shift);
} }
public double toDouble() {
return Double.longBitsToDouble(toDoubleBits());
}
/** /**
* Returns <code>true</code> if the value of this <code>Real</code> * Returns <code>true</code> if the value of this <code>Real</code>
* represents a mathematical integer. If the value is too large to * represents a mathematical integer. If the value is too large to
@ -6184,6 +6188,10 @@ public final class Real {
} }
} }
sign = tmpSign; sign = tmpSign;
if (index != length) {
// signal error
assign(NAN);
}
} }
//************************************************************************* //*************************************************************************