Java DecimalFormat 科学记数法问题

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1213747/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 15:39:51  来源:igfitidea点击:

Java DecimalFormat Scientific Notation Question

javaformattingdecimalscientific-notation

提问by Scott

I'm using Java's DecimalFormatclass to print out numbers in Scientific Notation. However, there is one problem that I have. I need the strings to be of fixed length regardless of the value, and the sign on the power of ten is throwing it off. Currently, this is what my format looks like:

我正在使用 Java 的DecimalFormat类以科学记数法打印数字。但是,我有一个问题。无论值如何,我都需要字符串是固定长度的,并且十次方的符号将其丢弃。目前,这就是我的格式:

DecimalFormat format = new DecimalFormat("0.0E0");

This gives me the following combinations: 1.0E1, 1.0E-1, -1.0E1, and -1.0E-1.

这给了我以下组合:1.0E1、1.0E-1、-1.0E1 和 -1.0E-1。

I can use setPositivePrefixto get: +1.0E1, +1.0E-1, -1.0E1, and -1.0E-1, or whatever I like, but it doesn't affect the sign of the power!

我可以使用setPositivePrefix来获得:+1.0E1、+1.0E-1、-1.0E1 和 -1.0E-1,或者我喜欢的任何东西,但它不影响幂的符号!

Is there any way to do this so that I can have fixed length strings? Thanks!

有没有办法做到这一点,以便我可以拥有固定长度的字符串?谢谢!

Edit: Ah, so there's no way to do it using Java's existing DecimalFormatAPI? Thanks for the suggestions! I think I may have to subclass DecimalFormatbecause I am limited by the interface that is already in place.

编辑:啊,所以没有办法使用 Java 现有的DecimalFormatAPI来做到这一点?感谢您的建议!我想我可能必须继承 DecimalFormat 的子类,因为我受到已经到位的接口的限制。

采纳答案by Carl Manaster

Here's one way. Hokey, perhaps, but it works...

这是一种方法。Hokey,也许,但它有效......

public class DecimalFormatTest extends TestCase {
    private static class MyFormat extends NumberFormat {
        private final DecimalFormat decimal;

        public MyFormat(String pattern) {
            decimal = new DecimalFormat(pattern);
        }

        public StringBuffer format(double number, StringBuffer toAppendTo, FieldPosition pos) {
            StringBuffer sb = new StringBuffer();
            sb.append(modified(Math.abs(number) > 1.0, decimal.format(number, toAppendTo, pos).toString()));
            return sb;
        }

        private String modified(boolean large, String s) {
            return large ? s.replace("E", "E+") : s;
        }

        public StringBuffer format(long number, StringBuffer toAppendTo, FieldPosition pos) {
            StringBuffer sb = new StringBuffer();
            sb.append(modified(true, decimal.format(number, toAppendTo, pos).toString()));
            return sb;
        }

        public Number parse(String source, ParsePosition parsePosition) {
            return decimal.parse(source, parsePosition);
        }

        public void setPositivePrefix(String newValue) {
            decimal.setPositivePrefix(newValue);
        }
    }
    private MyFormat    format;

    protected void setUp() throws Exception {
        format = new MyFormat("0.0E0");
        format.setPositivePrefix("+");
    }

    public void testPositiveLargeNumber() throws Exception {
        assertEquals("+1.0E+2", format.format(100.0));
    }

    public void testPositiveSmallNumber() throws Exception {
        assertEquals("+1.0E-2", format.format(0.01));
    }

    public void testNegativeLargeNumber() throws Exception {
        assertEquals("-1.0E+2", format.format(-100.0));
    }

    public void testNegativeSmallNumber() throws Exception {
        assertEquals("-1.0E-2", format.format(-0.01));
    }
}

Alternatively you could subclassDecimalFormat, but I find it generally cleaner not to subclass from concrete classes.

或者,您可以对DecimalFormat 进行子类化,但我发现不从具体类中子类化通常更清晰。

回答by Enrico Scantamburlo

This worked form me,

这对我有用,

DecimalFormatSymbols SYMBOLS = DecimalFormatSymbols.getInstance(Locale.US);

    if (value > 1 || value < -1) {
        SYMBOLS.setExponentSeparator("e+");
    } else {
        SYMBOLS.setExponentSeparator("e");
    }

    DecimalFormat format = new DecimalFormat(sb.toString(), SYMBOLS);

回答by Grant Wagner

Could you use printf()instead:

你可以用printf()

Format format = new DecimalFormat("0.0E0");
Double d = new Double(.01);
System.out.println(format.format(d));
System.out.printf("%1.1E\n", d);
d = new Double(100);
System.out.println(format.format(d));
System.out.printf("%1.1E\n", d);

Output:

输出:

1.0E-2
1.0E-02
1.0E2
1.0E+02

If you need to output to a Stringinstead, you can use the information provided at Formatted Printing for Java (sprintf)to do that.

如果您需要输出到 a String,则可以使用Java 格式化打印 (sprintf) 中提供的信息来执行此操作。

EDIT: Wow, that PrintfFormat()thing is huge and seems to be unnecessary:

编辑:哇,那PrintfFormat()东西太大了,似乎没有必要:

OutputStream b = new ByteArrayOutputStream();
PrintStream p = new PrintStream(b);
p.printf("%1.1E", d);
System.out.println(b.toString());

I got the idea for the above code from Get an OutputStream into a String.

我从Get an OutputStream into a String 得到了上述代码的想法。

回答by sambuca

How to use?
See formatTestmethod.

如何使用?
formatTest方法。

if (value.compareTo(positive) == 1 || value.compareTo(negative) == -1)is useful for very large numbers

if (value.compareTo(positive) == 1 || value.compareTo(negative) == -1)对于非常大的数字很有用

/**
 * inspired by:<br>
 * https://stackoverflow.com/a/13065493/8356718
 * https://stackoverflow.com/a/18027214/8356718
 * https://stackoverflow.com/a/25794946/8356718
 */
public static String format(String number, int scale) {
    BigDecimal value = new BigDecimal(number);
    DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(Locale.US);
    BigDecimal positive = new BigDecimal(1);// scale is zero
    positive.setScale(0);// unnecessary
    BigDecimal negative = new BigDecimal(-1);// scale is zero
    negative.setScale(0);// unnecessary
    if (value.compareTo(positive) == 1 || value.compareTo(negative) == -1) {
        symbols.setExponentSeparator("e+");
    } else {
        symbols.setExponentSeparator("e");
    }
    DecimalFormat formatter = new DecimalFormat("0.0E0", symbols);
    formatter.setRoundingMode(RoundingMode.HALF_UP);
    formatter.setMinimumFractionDigits(scale);
    return formatter.format(value);
}

/**
 * set the scale automatically
 */
public static String format(String number) {
    BigDecimal value = new BigDecimal(number);
    return format(number, value.scale() > 0 ? value.precision() : value.scale());
}

/*
output:
----------
0e0
1.0e-2
-1.0e-2
1.234560e-5
-1.234560e-5
1e0
-1e0
3e+0
-3e+0
2e+2
-2e+2
----------
0.0000000000e0
1.0000000000e-2
-1.0000000000e-2
1.2345600000e-5
-1.2345600000e-5
1.0000000000e0
-1.0000000000e0
3.0000000000e+0
-3.0000000000e+0
2.0000000000e+2
-2.0000000000e+2
----------
*/
public static void formatTest() {
    System.out.println("----------");
    System.out.println(format("0"));
    System.out.println(format("0.01"));
    System.out.println(format("-0.01"));
    System.out.println(format("0.0000123456"));
    System.out.println(format("-0.0000123456"));
    System.out.println(format("1"));
    System.out.println(format("-1"));
    System.out.println(format("3"));
    System.out.println(format("-3"));
    System.out.println(format("200"));
    System.out.println(format("-200"));
    System.out.println("----------");
    System.out.println(format("0", 10));
    System.out.println(format("0.01", 10));
    System.out.println(format("-0.01", 10));
    System.out.println(format("0.0000123456", 10));
    System.out.println(format("-0.0000123456", 10));
    System.out.println(format("1", 10));
    System.out.println(format("-1", 10));
    System.out.println(format("3", 10));
    System.out.println(format("-3", 10));
    System.out.println(format("200", 10));
    System.out.println(format("-200", 10));
    System.out.println("----------");
}

回答by kstep

Why not use "0.0E+0" pattern instead? Note the plus sign before last zero.

为什么不使用“0.0E+0”模式呢?注意最后一个零之前的加号。