Number formatting

This commit is contained in:
serso
2016-04-10 22:46:05 +02:00
parent 64a58c2047
commit 858f3f32b2
4 changed files with 168 additions and 19 deletions

View File

@@ -9,6 +9,7 @@ import jscl.math.operator.Percent;
import jscl.math.operator.Rand;
import jscl.math.operator.matrix.OperatorsRegistry;
import jscl.text.ParseException;
import midpcalc.Real;
import org.solovyev.common.NumberFormatter;
import org.solovyev.common.math.MathRegistry;
import org.solovyev.common.msg.MessageRegistry;
@@ -19,6 +20,8 @@ import javax.annotation.Nullable;
import java.math.BigDecimal;
import java.util.List;
import static midpcalc.Real.NumberFormat.*;
public class JsclMathEngine implements MathEngine {
public static final AngleUnit DEFAULT_ANGLE_UNITS = AngleUnit.deg;
@@ -38,7 +41,7 @@ public class JsclMathEngine implements MathEngine {
};
private char groupingSeparator = GROUPING_SEPARATOR_DEFAULT;
private boolean roundResult = false;
private boolean scienceNotation = false;
private int numberFormat = FSE_NONE;
private int precision = 5;
private boolean useGroupingSeparator = false;
@Nonnull
@@ -166,11 +169,17 @@ public class JsclMathEngine implements MathEngine {
}
final NumberFormatter nf = numberFormatter.get();
nf.setGroupingSeparator(useGroupingSeparator ? groupingSeparator : NumberFormatter.NO_GROUPING);
nf.setPrecision(roundResult ? precision : NumberFormatter.DEFAULT_PRECISION);
if (scienceNotation) {
nf.useEngineeringFormat(NumberFormatter.DEFAULT_MAGNITUDE);
} else {
nf.useSimpleFormat();
nf.setPrecision(roundResult ? precision : NumberFormatter.NO_ROUNDING);
switch (numberFormat) {
case Real.NumberFormat.FSE_ENG:
nf.useEngineeringFormat(NumberFormatter.DEFAULT_MAGNITUDE);
break;
case FSE_SCI:
nf.useScientificFormat(NumberFormatter.DEFAULT_MAGNITUDE);
break;
default:
nf.useSimpleFormat();
break;
}
return nf.format(value, nb.radix).toString();
}
@@ -307,7 +316,14 @@ public class JsclMathEngine implements MathEngine {
}
public void setScienceNotation(boolean scienceNotation) {
this.scienceNotation = scienceNotation;
setNumberFormat(scienceNotation ? FSE_SCI : FSE_NONE);
}
public void setNumberFormat(int numberFormat) {
if (numberFormat != FSE_SCI && numberFormat != FSE_ENG && numberFormat != FSE_NONE) {
throw new IllegalArgumentException("Unsupported format: " + numberFormat);
}
this.numberFormat = numberFormat;
}
public char getGroupingSeparator() {

View File

@@ -5,21 +5,28 @@ import midpcalc.Real;
import javax.annotation.Nonnull;
import java.math.BigDecimal;
import static java.lang.Math.pow;
import static midpcalc.Real.NumberFormat.*;
public class NumberFormatter {
public static final int NO_GROUPING = 0;
public static final int DEFAULT_PRECISION = 16;
public static final int NO_ROUNDING = -1;
public static final int DEFAULT_MAGNITUDE = 5;
public static final int MAX_PRECISION = 16;
private final Real.NumberFormat numberFormat = new Real.NumberFormat();
private final Real real = new Real();
private int format = FSE_NONE;
private int simpleFormatMagnitude = DEFAULT_MAGNITUDE;
private int precision = DEFAULT_PRECISION;
private int precision = MAX_PRECISION;
private char groupingSeparator;
public void useScientificFormat(int simpleFormatMagnitude) {
this.format = FSE_SCI;
this.simpleFormatMagnitude = simpleFormatMagnitude;
}
public void useEngineeringFormat(int simpleFormatMagnitude) {
this.format = FSE_ENG;
this.simpleFormatMagnitude = simpleFormatMagnitude;
@@ -49,19 +56,27 @@ public class NumberFormatter {
throw new IllegalArgumentException("Unsupported radix: " + radix);
}
double absValue = Math.abs(value);
final boolean dec = radix == 10;
final boolean fixedFormat = !dec || format == FSE_NONE || Math.pow(10, -simpleFormatMagnitude) <= absValue && absValue < Math.pow(10, simpleFormatMagnitude);
final boolean simpleFormat = useSimpleFormat(radix, absValue);
if (fixedFormat) {
final int newScale = (int) (precision * Math.max(1, radix / 10f));
final int effectivePrecision = precision == NO_ROUNDING ? MAX_PRECISION : precision;
if (simpleFormat) {
final int newScale = (int) (effectivePrecision * Math.max(1, radix / 10f));
value = BigDecimal.valueOf(value).setScale(newScale, BigDecimal.ROUND_HALF_UP).doubleValue();
absValue = Math.abs(value);
}
numberFormat.fse = fixedFormat ? FSE_FIX : FSE_ENG;
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 = precision;
numberFormat.precision = effectivePrecision;
numberFormat.base = radix;
numberFormat.maxwidth = fixedFormat ? 100 : 30;
numberFormat.maxwidth = simpleFormat ? 100 : 30;
if (radix == 2 && value < 0) {
return "-" + prepare(absValue);
@@ -69,6 +84,23 @@ public class NumberFormatter {
return prepare(value);
}
private boolean useSimpleFormat(int radix, double absValue) {
if (radix != 10) {
return true;
}
if (absValue < pow(10, -MAX_PRECISION)) {
// should never use simple format for small numbers
return false;
}
if (format == FSE_NONE) {
return true;
}
if (pow(10, -simpleFormatMagnitude) <= absValue && absValue < pow(10, simpleFormatMagnitude)) {
return true;
}
return false;
}
@Nonnull
private CharSequence prepare(double value) {
return stripZeros(realFormat(value)).replace('e', 'E');