Format BigInteger directly
This commit is contained in:
parent
9e9e856c24
commit
85b9cdc56a
@ -17,6 +17,7 @@ import org.solovyev.common.msg.Messages;
|
|||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.math.BigInteger;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static midpcalc.Real.NumberFormat.*;
|
import static midpcalc.Real.NumberFormat.*;
|
||||||
@ -166,6 +167,10 @@ public class JsclMathEngine implements MathEngine {
|
|||||||
return constant.getName();
|
return constant.getName();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return prepareNumberFormatter(nb).format(value, nb.radix).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private NumberFormatter prepareNumberFormatter(@Nonnull NumeralBase nb) {
|
||||||
final NumberFormatter nf = numberFormatter.get();
|
final NumberFormatter nf = numberFormatter.get();
|
||||||
nf.setGroupingSeparator(useGroupingSeparator ? getGroupingSeparatorChar(nb) : NumberFormatter.NO_GROUPING);
|
nf.setGroupingSeparator(useGroupingSeparator ? getGroupingSeparatorChar(nb) : NumberFormatter.NO_GROUPING);
|
||||||
nf.setPrecision(roundResult ? precision : NumberFormatter.NO_ROUNDING);
|
nf.setPrecision(roundResult ? precision : NumberFormatter.NO_ROUNDING);
|
||||||
@ -180,7 +185,22 @@ public class JsclMathEngine implements MathEngine {
|
|||||||
nf.useSimpleFormat();
|
nf.useSimpleFormat();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return nf.format(value, nb.radix).toString();
|
return nf;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String format(@Nonnull BigInteger value) throws NumeralBaseException {
|
||||||
|
return format(value, numeralBase);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
public String format(@Nonnull BigInteger value, @Nonnull NumeralBase nb) throws NumeralBaseException {
|
||||||
|
if (nb == NumeralBase.dec) {
|
||||||
|
if (BigInteger.ZERO.equals(value)) {
|
||||||
|
return "0";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return prepareNumberFormatter(nb).format(value, nb.radix).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
@ -6,6 +6,7 @@ import jscl.math.operator.Operator;
|
|||||||
import org.solovyev.common.math.MathRegistry;
|
import org.solovyev.common.math.MathRegistry;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
|
||||||
public interface MathContext {
|
public interface MathContext {
|
||||||
|
|
||||||
@ -46,6 +47,8 @@ public interface MathContext {
|
|||||||
@Nonnull
|
@Nonnull
|
||||||
String format(double value) throws NumeralBaseException;
|
String format(double value) throws NumeralBaseException;
|
||||||
|
|
||||||
|
String format(@Nonnull BigInteger value) throws NumeralBaseException;
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
String format(double value, @Nonnull NumeralBase nb) throws NumeralBaseException;
|
String format(double value, @Nonnull NumeralBase nb) throws NumeralBaseException;
|
||||||
|
|
||||||
|
@ -352,8 +352,7 @@ public final class JsclInteger extends Generic {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
// todo serso: actually better way is to provide custom format() method for integers and not to convert integer to double
|
return JsclMathEngine.getInstance().format(content);
|
||||||
return JsclMathEngine.getInstance().format(this.content.doubleValue());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toJava() {
|
public String toJava() {
|
||||||
|
@ -1,16 +1,13 @@
|
|||||||
package org.solovyev.common;
|
package org.solovyev.common;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
|
|
||||||
import midpcalc.Real;
|
import midpcalc.Real;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
|
||||||
import static java.lang.Math.pow;
|
import static java.lang.Math.pow;
|
||||||
import static midpcalc.Real.NumberFormat.FSE_ENG;
|
import static midpcalc.Real.NumberFormat.*;
|
||||||
import static midpcalc.Real.NumberFormat.FSE_FIX;
|
|
||||||
import static midpcalc.Real.NumberFormat.FSE_NONE;
|
|
||||||
import static midpcalc.Real.NumberFormat.FSE_SCI;
|
|
||||||
|
|
||||||
public class NumberFormatter {
|
public class NumberFormatter {
|
||||||
|
|
||||||
@ -55,10 +52,13 @@ public class NumberFormatter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
public CharSequence format(double value, int radix) {
|
public CharSequence format(@Nonnull BigInteger value) {
|
||||||
if (radix != 2 && radix != 8 && radix != 10 && radix != 16) {
|
return format(value, 10);
|
||||||
throw new IllegalArgumentException("Unsupported radix: " + radix);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
public CharSequence format(double value, int radix) {
|
||||||
|
checkRadix(radix);
|
||||||
double absValue = Math.abs(value);
|
double absValue = Math.abs(value);
|
||||||
final boolean simpleFormat = useSimpleFormat(radix, absValue);
|
final boolean simpleFormat = useSimpleFormat(radix, absValue);
|
||||||
|
|
||||||
@ -88,6 +88,39 @@ public class NumberFormatter {
|
|||||||
return prepare(value);
|
return prepare(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
public CharSequence format(@Nonnull BigInteger value, int radix) {
|
||||||
|
checkRadix(radix);
|
||||||
|
final BigInteger absValue = value.abs();
|
||||||
|
final boolean simpleFormat = useSimpleFormat(radix, absValue);
|
||||||
|
|
||||||
|
final int effectivePrecision = precision == NO_ROUNDING ? MAX_PRECISION : precision;
|
||||||
|
if (simpleFormat) {
|
||||||
|
numberFormat.fse = FSE_FIX;
|
||||||
|
} else if (format == FSE_NONE) {
|
||||||
|
// originally, a simple format was requested but we have to use something more appropriate, f.e. scientific
|
||||||
|
// format
|
||||||
|
numberFormat.fse = FSE_SCI;
|
||||||
|
} else {
|
||||||
|
numberFormat.fse = format;
|
||||||
|
}
|
||||||
|
numberFormat.thousand = groupingSeparator;
|
||||||
|
numberFormat.precision = effectivePrecision;
|
||||||
|
numberFormat.base = radix;
|
||||||
|
numberFormat.maxwidth = simpleFormat ? 100 : 30;
|
||||||
|
|
||||||
|
if (radix == 2 && value.compareTo(BigInteger.ZERO) < 0) {
|
||||||
|
return "-" + prepare(absValue);
|
||||||
|
}
|
||||||
|
return prepare(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkRadix(int radix) {
|
||||||
|
if (radix != 2 && radix != 8 && radix != 10 && radix != 16) {
|
||||||
|
throw new IllegalArgumentException("Unsupported radix: " + radix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private boolean useSimpleFormat(int radix, double absValue) {
|
private boolean useSimpleFormat(int radix, double absValue) {
|
||||||
if (radix != 10) {
|
if (radix != 10) {
|
||||||
return true;
|
return true;
|
||||||
@ -103,17 +136,41 @@ public class NumberFormatter {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean useSimpleFormat(int radix, @Nonnull BigInteger absValue) {
|
||||||
|
if (radix != 10) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (format == FSE_NONE) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (absValue.compareTo(BigInteger.valueOf((long) pow(10, simpleFormatMagnitude))) < 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
private CharSequence prepare(double value) {
|
private CharSequence prepare(double value) {
|
||||||
return stripZeros(realFormat(value)).replace('e', 'E');
|
return stripZeros(realFormat(value)).replace('e', 'E');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
private CharSequence prepare(@Nonnull BigInteger value) {
|
||||||
|
return stripZeros(realFormat(value)).replace('e', 'E');
|
||||||
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
private String realFormat(double value) {
|
private String realFormat(double value) {
|
||||||
real.assign(Double.toString(value));
|
real.assign(Double.toString(value));
|
||||||
return real.toString(numberFormat);
|
return real.toString(numberFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
private String realFormat(@Nonnull BigInteger value) {
|
||||||
|
real.assign(value.toString());
|
||||||
|
return real.toString(numberFormat);
|
||||||
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
private String stripZeros(@Nonnull String s) {
|
private String stripZeros(@Nonnull String s) {
|
||||||
int dot = -1;
|
int dot = -1;
|
||||||
|
@ -3,7 +3,10 @@ package org.solovyev.common;
|
|||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
|
||||||
import static java.lang.Math.pow;
|
import static java.lang.Math.pow;
|
||||||
|
import static java.math.BigInteger.TEN;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.solovyev.common.NumberFormatter.DEFAULT_MAGNITUDE;
|
import static org.solovyev.common.NumberFormatter.DEFAULT_MAGNITUDE;
|
||||||
import static org.solovyev.common.NumberFormatter.NO_ROUNDING;
|
import static org.solovyev.common.NumberFormatter.NO_ROUNDING;
|
||||||
@ -99,32 +102,66 @@ public class NumberFormatterTest {
|
|||||||
// testing simple format with and without rounding
|
// testing simple format with and without rounding
|
||||||
private void testSimpleFormat() {
|
private void testSimpleFormat() {
|
||||||
assertEquals("0.00001", numberFormatter.format(pow(10, -5)));
|
assertEquals("0.00001", numberFormatter.format(pow(10, -5)));
|
||||||
|
|
||||||
assertEquals("100", numberFormatter.format(pow(10, 2)));
|
assertEquals("100", numberFormatter.format(pow(10, 2)));
|
||||||
|
assertEquals("1", numberFormatter.format(BigInteger.ONE));
|
||||||
|
assertEquals("1000", numberFormatter.format(BigInteger.valueOf(1000)));
|
||||||
|
|
||||||
assertEquals("1000000000000000000", numberFormatter.format(pow(10, 18)));
|
assertEquals("1000000000000000000", numberFormatter.format(pow(10, 18)));
|
||||||
|
assertEquals("1000000000000000000", numberFormatter.format(BigInteger.valueOf(10).pow(18)));
|
||||||
|
|
||||||
assertEquals("1E19", numberFormatter.format(pow(10, 19)));
|
assertEquals("1E19", numberFormatter.format(pow(10, 19)));
|
||||||
|
assertEquals("1E19", numberFormatter.format(BigInteger.valueOf(10).pow(19)));
|
||||||
|
|
||||||
assertEquals("1E20", numberFormatter.format(pow(10, 20)));
|
assertEquals("1E20", numberFormatter.format(pow(10, 20)));
|
||||||
|
assertEquals("1E20", numberFormatter.format(BigInteger.valueOf(10).pow(20)));
|
||||||
|
|
||||||
assertEquals("1E100", numberFormatter.format(pow(10, 100)));
|
assertEquals("1E100", numberFormatter.format(pow(10, 100)));
|
||||||
|
assertEquals("1E100", numberFormatter.format(BigInteger.valueOf(10).pow(100)));
|
||||||
|
|
||||||
assertEquals("0.01", numberFormatter.format(pow(10, -2)));
|
assertEquals("0.01", numberFormatter.format(pow(10, -2)));
|
||||||
|
|
||||||
assertEquals("5000000000000000000", numberFormatter.format(5000000000000000000d));
|
assertEquals("5000000000000000000", numberFormatter.format(5000000000000000000d));
|
||||||
|
assertEquals("5000000000000000000", numberFormatter.format(BigInteger.valueOf(5000000000000000000L)));
|
||||||
|
|
||||||
assertEquals("5000000000000000000", numberFormatter.format(5000000000000000001d));
|
assertEquals("5000000000000000000", numberFormatter.format(5000000000000000001d));
|
||||||
|
assertEquals("5000000000000000001", numberFormatter.format(BigInteger.valueOf(5000000000000000001L)));
|
||||||
|
|
||||||
assertEquals("5999999999999994900", numberFormatter.format(5999999999999994999d));
|
assertEquals("5999999999999994900", numberFormatter.format(5999999999999994999d));
|
||||||
|
assertEquals("5999999999999994999", numberFormatter.format(BigInteger.valueOf(5999999999999994999L)));
|
||||||
|
|
||||||
assertEquals("5E19", numberFormatter.format(50000000000000000000d));
|
assertEquals("5E19", numberFormatter.format(50000000000000000000d));
|
||||||
|
assertEquals("5E19", numberFormatter.format(BigInteger.valueOf(5L).multiply(TEN.pow(19))));
|
||||||
|
|
||||||
assertEquals("5E40", numberFormatter.format(50000000000000000000000000000000000000000d));
|
assertEquals("5E40", numberFormatter.format(50000000000000000000000000000000000000000d));
|
||||||
|
assertEquals("5E40", numberFormatter.format(BigInteger.valueOf(5L).multiply(TEN.pow(40))));
|
||||||
}
|
}
|
||||||
|
|
||||||
// testing scientific format with and without rounding
|
// testing scientific format with and without rounding
|
||||||
private void testScientificFormat() {
|
private void testScientificFormat() {
|
||||||
assertEquals("0.00001", numberFormatter.format(pow(10, -5)));
|
assertEquals("0.00001", numberFormatter.format(pow(10, -5)));
|
||||||
assertEquals("1E-6", numberFormatter.format(pow(10, -6)));
|
assertEquals("1E-6", numberFormatter.format(pow(10, -6)));
|
||||||
|
|
||||||
assertEquals("100", numberFormatter.format(pow(10, 2)));
|
assertEquals("100", numberFormatter.format(pow(10, 2)));
|
||||||
|
assertEquals("100", numberFormatter.format(TEN.pow(2)));
|
||||||
|
|
||||||
assertEquals("10000", numberFormatter.format(pow(10, 4)));
|
assertEquals("10000", numberFormatter.format(pow(10, 4)));
|
||||||
|
assertEquals("10000", numberFormatter.format(TEN.pow(4)));
|
||||||
|
|
||||||
assertEquals("1E5", numberFormatter.format(pow(10, 5)));
|
assertEquals("1E5", numberFormatter.format(pow(10, 5)));
|
||||||
|
assertEquals("1E5", numberFormatter.format(TEN.pow(5)));
|
||||||
|
|
||||||
assertEquals("1E18", numberFormatter.format(pow(10, 18)));
|
assertEquals("1E18", numberFormatter.format(pow(10, 18)));
|
||||||
|
assertEquals("1E18", numberFormatter.format(TEN.pow(18)));
|
||||||
|
|
||||||
assertEquals("1E19", numberFormatter.format(pow(10, 19)));
|
assertEquals("1E19", numberFormatter.format(pow(10, 19)));
|
||||||
|
assertEquals("1E19", numberFormatter.format(TEN.pow( 19)));
|
||||||
|
|
||||||
assertEquals("1E20", numberFormatter.format(pow(10, 20)));
|
assertEquals("1E20", numberFormatter.format(pow(10, 20)));
|
||||||
|
assertEquals("1E20", numberFormatter.format(TEN.pow(20)));
|
||||||
|
|
||||||
assertEquals("1E100", numberFormatter.format(pow(10, 100)));
|
assertEquals("1E100", numberFormatter.format(pow(10, 100)));
|
||||||
|
assertEquals("1E100", numberFormatter.format(TEN.pow(100)));
|
||||||
|
|
||||||
assertEquals("0.01", numberFormatter.format(pow(10, -2)));
|
assertEquals("0.01", numberFormatter.format(pow(10, -2)));
|
||||||
assertEquals("1E-17", numberFormatter.format(pow(10, -17)));
|
assertEquals("1E-17", numberFormatter.format(pow(10, -17)));
|
||||||
|
Loading…
Reference in New Issue
Block a user