【问题标题】:DecimalFormat - Format decimal to preserve variable amount of trailing zerosDecimalFormat - 格式化十进制以保留可变数量的尾随零
【发布时间】:2017-10-26 18:47:44
【问题描述】:

在使用 DecimalFormat 格式化为字符串时,我需要保留数字的小数位数,特别是尾随零。我需要使用 DecimalFormat,因为我还需要避免使用科学记数法来处理大数,正如 here 所见,这是最好的方法。但是,正如您在那篇文章中看到的那样,提供的代码还删除了尾随零,而我想保留它们。

1.00 -> "1.00"
1.000 -> "1.000"

我见过很多涉及固定小数位数的问题,但在我的情况下,我需要考虑可变数量的小数位数。我研究了计算小数位数,但由于我的输入也可以是 Double(除了 BigDecimal),因此似乎没有可靠的方法来计算所有数字的小数点后的位数。 Double.toString() 不起作用,因为对于非常小和非常大的数字,双精度数会分解为指数符号。请参阅 here 了解有关为什么难以计算双精度数的更多信息。

【问题讨论】:

    标签: java double bigdecimal decimalformat


    【解决方案1】:

    “保留”尾随零?

    double 值不知道您想看到多少个尾随零。它只是一个数字,而1.001.000是同一个数字,即数字1。您所问的问题无法通过 double 值完成。

    现在,BigDecimal 确实记住了尾随零的数量,所以如果您想打印 BigDecimal 值,保留数字的比例,但确保它永远不会以科学计数法打印,不要使用DecimalFormat,而是使用toPlainString()

    返回此BigDecimal 的字符串表示形式没有指数字段


    更新

    如果您想根据需要打印带有尽可能多的小数位数的double 值(即没有尾随零),并且想确保它永远不会以科学计数法打印,请使用具有非常高的@987654335 的DecimalFormat @和非常高的setMaximumFractionDigits

    “非常高”是指超出double 范围的值,因此999 是一个很好的“整数”,尽管330 足够高。

    测试

    DecimalFormat fmt = new DecimalFormat("0");
    fmt.setMaximumIntegerDigits(330);
    fmt.setMaximumFractionDigits(330);
    
    System.out.println("0.0123400  = " + 0.0123400               + "   = " + fmt.format(0.0123400));
    System.out.println("123400.00  = " + 123400.00                + "  = " + fmt.format(123400.00));
    System.out.println("NaN        = " + Double.NaN          + "       = " + fmt.format(Double.NaN));
    System.out.println("-INFINITY  = " + Double.NEGATIVE_INFINITY  + " = " + fmt.format(Double.NEGATIVE_INFINITY));
    System.out.println("+INFINITY  = " + Double.POSITIVE_INFINITY + "  = " + fmt.format(Double.POSITIVE_INFINITY));
    System.out.println("MIN_NORMAL = " + Double.MIN_NORMAL               + " = " + fmt.format(Double.MIN_NORMAL));
    System.out.println("MIN_VALUE  = " + Double.MIN_VALUE + "                = " + fmt.format(Double.MIN_VALUE));
    System.out.println("MAX_VALUE  = " + Double.MAX_VALUE               + "  = " + fmt.format(Double.MAX_VALUE));
    

    输出

    0.0123400  = 0.01234   = 0.01234
    123400.00  = 123400.0  = 123400
    NaN        = NaN       = �
    -INFINITY  = -Infinity = -∞
    +INFINITY  = Infinity  = ∞
    MIN_NORMAL = 2.2250738585072014E-308 = 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072014
    MIN_VALUE  = 4.9E-324                = 0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000049
    MAX_VALUE  = 1.7976931348623157E308  = 179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
    

    【讨论】:

    • 不幸的是,输入也可以是双精度。因此,如果我尝试使用值 1.2 列出的 BigDecimal 方法,则输出如下: new BigDecimal(1.2).toPlainString() 结果为 1.1999999999999999555910790149937383830547332763671875'
    • @adiadi 不要使用BigDecimal(double) 构造函数。请改用BigDecimal.valueOf(double)。 javadoc 甚至告诉您:这通常是将double(或float)转换为BigDecimal 的首选方法,因为返回的值等于从构造BigDecimal 得到的值使用Double.toString(double)的结果。
    • 实际上,1.01.0001 在以浮点二进制表示时(例如 doublefloat)在技术上是不同的值。
    • @JarrodRoberson 1.01.0001 在浮点二进制文件(例如 doublefloat)中完全相同,例如作为float,这三个都是字节3f 80 00 00。它们在BigDecimal 中不同,但肯定与浮点值相同。
    【解决方案2】:

    double(无精度,始终为近似值)或BigDecimal

    使用 BigDecimal 作为new BigDecimal("2.00") 定义两位数字的正确小数位数(精度)。您可以通过编程方式设置比例。

    对于数据库和计算(如金融)BigDecimal 很好。

    BigDecimal.toPlainString() 可以避免输出的科学表示。

    对于double,可以使用以下格式

    s = String.format("%10.2f", 13.5789); // "   13.58"
    

    所有这些都是小数点,没有千位分隔符。

    国际化(本地化)软件将使用带有区域设置(显式或默认平台区域设置)的MessageFormat

    Locale.setDefault(new Locale("bg", "BG"));
    s = MessageFormat.format("Number: {0, number, #.##}, "
                + "amount: {1, number, currency}",
                42.125, 19.99);
    

    【讨论】:

    • 关于使用 BigDecimal:我无法确定双精度输入的正确比例。在所有其他情况下,我可以这样做,但如果它是双精度数,我无法这样做,因为正如您所说,双精度数具有近似值。假设输入为 1.200。我需要将其转换为字符串。如何使用 DecimalFormat 做到这一点而不对比例进行硬编码?
    • @adiadi 你不能。作为double 值,1.200 与您已经知道1.2完全相同相同,因为您的第二个链接中的answer问题已经告诉你了,那你为什么要问?
    • new BigDecimal("1.200")(文本输入)或new BigDecimal(1.2).setScale(3)(是的,编程为 1.2 == 1.200)。
    • @adiadi 问题与 double 的近似性质无关。 Double 没有留出任何位来记住许多尾随零。 1.0, 1.00, 1.000, ... 都用double表示为0x3ff0_0000_0000_0000,没有舍入误差。
    猜你喜欢
    • 1970-01-01
    • 2016-11-13
    • 1970-01-01
    • 1970-01-01
    • 2013-08-20
    • 1970-01-01
    • 2012-07-25
    • 1970-01-01
    • 2021-06-20
    相关资源
    最近更新 更多