2

我正在尝试使用 DecimalFormat 转换双精度值的小数分隔符,同时保留原始数字的所有小数。DecimalFormatter 接受格式为“0.##”的模式,例如。由于我必须使用具有不同小数的数字,因此这将不起作用,因为始终需要在模式中指定小数位数。

我正在寻找一种方法来解决这个问题。

我试过String.format。DecimaFormatter 和 NumberFormatter

理想情况下,我想要的是以下内容:

  private static final ThreadLocal< DecimalFormat > formatter = new ThreadLocal< DecimalFormat >() 
  {
    @Override
    protected DecimalFormat initialValue() 
    {
    // n should be any number of decimals without having to specify them.
      return new DecimalFormat("0.0#n");     
    }
  };

一些例子:

DecimalFormat df = new DecimalFormat("0.0##");
System.out.println(df.format(2.456))
System.out.println(df.format(2.1));

结果:

2,456 -> Good
2,100 -> Not good

我想设置一个模式/正则表达式,它适用于小数点分隔符后任意位数的双精度,例如:

2,456 -> Good
2,1 -> Good
3,3453456345234 -> Good
4

3 回答 3

3

Java 中的数字(通常只是数字)没有固定的小数位数。1.1, 1.10, 和1.100都是完全相同的数字。

您可以找出默认格式将使用多少个地方,例如:

String str = num.toString();
int decimal = str.indexOf('.');
int places = decimal <= 0 ? 0 : str.length - decimal;

...然后在使用格式化程序时指定很多地方。

于 2019-05-13T14:58:20.473 回答
0

DecimalFormat有 16种设置方法来控制输出。您在构造函数中指定的模式字符串只是设置大多数这些值的便捷方式。

要控制输出的语言环境,您可以DecimalFormatSymbols在构造函数或setter 方法中指定。

由于您想要无限制的小数位,而且您似乎想要至少一位小数,您需要调用 setter 方法,因为使用模式字符串无法指定无限制。

例子

private static void test(Locale locale) {
    DecimalFormat fmt = new DecimalFormat("0.0", DecimalFormatSymbols.getInstance(locale));
    //fmt.setMaximumIntegerDigits(Integer.MAX_VALUE); // already set by pattern
    //fmt.setMinimumIntegerDigits(1);                 // already set by pattern
    //fmt.setMinimumFractionDigits(1);                // already set by pattern
    fmt.setMaximumFractionDigits(Integer.MAX_VALUE);
    //fmt.setGroupingUsed(false);                     // already set by pattern

    System.out.println(locale.toLanguageTag() + " (" + locale.getDisplayLanguage(Locale.US) +
                                               " - " + locale.getDisplayCountry(Locale.US) + ")");
    System.out.println("  " + fmt.format(123456789));
    System.out.println("  " + fmt.format(2.456));
    System.out.println("  " + fmt.format(2.1));
    System.out.println("  " + fmt.format(3.3453456345234));
}

public static void main(String[] args) {
    test(Locale.US);
    test(Locale.GERMANY);
    test(Locale.forLanguageTag("ar-EG"));
}

输出(OpenJDK 11.0.1)

en-US (English - United States)
  123456789.0
  2.456
  2.1
  3.3453456345234
de-DE (German - Germany)
  123456789,0
  2,456
  2,1
  3,3453456345234
ar-EG (Arabic - Egypt)
  ١٢٣٤٥٦٧٨٩٫٠
  ٢٫٤٥٦
  ٢٫١
  ٣٫٣٤٥٣٤٥٦٣٤٥٢٣٤
于 2019-05-13T15:30:13.753 回答
0

所以你有了

double[] floats = { 3.20, 4.500, 6.34, 1.0000 };
BigDecimal[] fixeds = {
    new BigDecimal("3.20"),
    new BigDecimal("4.500"),
    new BigDecimal("6.34"),
    new BigDecimal("1.0000")
};

并希望将它们格式化,但已本地化。

好消息是 BigDecimal 的定点数保持精度(使用字符串构造函数)。坏消息是浮点总是一个近似值,乘以 2 的(负)幂之和。所以 3.20 实际上可能是 3.19999987 或 3.20000043。

它们没有固定的小数。即使没有近似误差 3.2 == 3.20 == 3.200。

所以转换为 BigDecimal(非常难看),并消除近似误差:1000*3.2 != 3200.0。

BigDecimal value = new BigDecimal("5.1000");
NumberFormat df = NumberFormat.getInstance(Locale.KOREA);
df.setMinimumFractionDigits(value.getScale()); // 4
String s = df.format(value);
于 2019-05-13T15:00:19.357 回答