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;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log;
import com.google.common.base.Strings;
import jscl.JsclMathEngine;
@ -101,17 +100,21 @@ final class Converter {
return 0;
}
public static double parse(@NonNull String value) {
@NonNull
public static Real parse(@NonNull String value) throws NumberFormatException {
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());
if (!TextUtils.isEmpty(groupingSeparator)) {
if (groupingSeparator.length() > 0) {
value = value.replace(groupingSeparator, "");
}
final Real real = new Real(value, base);
final long bits = real.toDoubleBits();
return Double.longBitsToDouble(bits);
if (real.isNan()) {
throw new NumberFormatException();
}
return real;
}
}

View File

@ -21,39 +21,21 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ImageButton;
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 android.widget.*;
import butterknife.Bind;
import butterknife.ButterKnife;
import org.solovyev.android.calculator.*;
import org.solovyev.android.calculator.keyboard.FloatingKeyboard;
import org.solovyev.android.calculator.keyboard.FloatingKeyboardWindow;
import org.solovyev.android.calculator.keyboard.FloatingNumberKeyboard;
import org.solovyev.android.calculator.math.MathUtils;
import org.solovyev.android.calculator.view.EditTextCompat;
import java.util.Comparator;
import javax.annotation.Nonnull;
import javax.inject.Inject;
import java.util.Comparator;
import butterknife.Bind;
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;
import static org.solovyev.android.calculator.UiPreferences.Converter.*;
public class ConverterFragment extends BaseDialogFragment
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();
if (TextUtils.isEmpty(value)) {
if (validate) {
setError(labelFrom, "Empty");
setError(labelFrom, R.string.cpp_nan);
}
return;
}
@ -345,7 +327,7 @@ public class ConverterFragment extends BaseDialogFragment
} catch (RuntimeException e) {
editTextTo.setText("");
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 {
@NonNull
String convert(@NonNull Convertible to, @NonNull String value);
String convert(@NonNull Convertible to, @NonNull String value) throws NumberFormatException;
@NonNull
Named<Convertible> named(@NonNull Context context);

View File

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

View File

@ -34,7 +34,7 @@ final class UnitConvertible implements Convertible {
@NonNull
@Override
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);
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>
* <p/>
* <p>The number is parsed until the end of the string or an unknown
* character is encountered, then silently returns even if the whole
* string has not been parsed. Please note that specifying an
* character is encountered. Note that in case of latter this Real becomes
* NAN. Please note that specifying an
* excessive number of digits in base-10 may in fact decrease the
* accuracy of the result because of the extra multiplications performed.
* <p/>
@ -2243,6 +2243,10 @@ public final class Real {
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>
* represents a mathematical integer. If the value is too large to
@ -6184,6 +6188,10 @@ public final class Real {
}
}
sign = tmpSign;
if (index != length) {
// signal error
assign(NAN);
}
}
//*************************************************************************