17

我试图在我的双精度值的小数分隔符后去掉不必要的符号。我是这样做的:

DecimalFormat format = new DecimalFormat("#.#####");
value = Double.valueOf(format.format(41251.50000000012343));

但是当我运行这段代码时,它会抛出:

java.lang.NumberFormatException: For input string: "41251,5"
    at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1224)
    at java.lang.Double.valueOf(Double.java:447)
    at ...

正如我所看到的,它Double.valueOf()适用"11.1"于像"11,1". 我该如何解决这个问题?有没有比类似的更优雅的方式

Double.valueOf(format.format(41251.50000000012343).replaceAll(",", "."));

有没有办法覆盖DecimalFormat类的默认小数分隔符值?还有其他想法吗?

4

10 回答 10

88

经过

在我的双精度值的小数分隔符后去掉不必要的符号

你真的是说你想四舍五入到小数点后五位吗?然后只需使用

value = Math.round(value*1e5)/1e5;

Math.floor(value*1e5)/1e5(当然,如果你真的想切断其他数字,你也可以)

编辑

使用此方法(或任何浮点舍入)时要非常小心。对于像 265.335 这样简单的东西,它就失败了。265.335 * 100(2位精度)的中间结果是26533.499999999996。这意味着它被四舍五入到 265.33。从浮点数转换为实十进制数时,存在固有的问题。在https://stackoverflow.com/a/12684082/144578上查看 EJP 的答案-如何在 Java 中将数字四舍五入到 n 位小数

于 2010-04-22T13:25:34.867 回答
24

问题是您的十进制格式将您的值转换为本地化字符串。我猜你的语言环境的默认小数分隔符带有' ,'。这经常发生在法国地区或世界其他地区。

基本上,您需要做的是使用“。”创建格式化日期。分隔符所以Double.valueOf可以读取它。如评论所示,您也可以使用相同的格式来解析值,而不是使用Double.valueOf.

DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance();
symbols.setDecimalSeparator('.');
DecimalFormat format = new DecimalFormat("#.#####", symbols);
value = format.parse(format.format(41251.50000000012343));
于 2010-04-22T13:25:37.647 回答
6

用于Locale.getDefault()获取您也可以设置的系统的小数分隔符。您不能同时有两个不同的分隔符,因为另一个通常用作数千个分隔符:2.001.000,23 <=> 2,001,000.23

于 2010-04-22T13:19:09.997 回答
6

您的格式化字符串.用作小数点分隔符,而异常抱怨,指向区域设置问题的事实;即 DecimalFormat 使用与 Double.valueOf 预期不同的区域设置来格式化数字。

通常,您应该NumberFormat基于特定的 Locale 构造一个。

Locale myLocale = ...;
NumberFormat f = NumberFormat.getInstance(myLocale);

来自DecimalFormat的 JavaDocs :

要获取特定语言环境(包括默认语言环境)的 NumberFormat,请调用 NumberFormat 的工厂方法之一,例如 getInstance()。通常,不要直接调用 DecimalFormat 构造函数,因为 NumberFormat 工厂方法可能返回 DecimalFormat 以外的子类。

然而,正如 BalusC 指出的那样,尝试将双精度格式化为字符串,然后将字符串解析回双精度是一种非常糟糕的代码气味。我怀疑您正在处理您期望固定精度十进制数(例如货币金额)但遇到问题的问题,因为 double 是浮点数,这意味着许多值(例如0.1)无法表达精确地作为双/浮点数。如果是这种情况,处理固定精度十进制数的正确方法是使用BigDecimal.

于 2010-04-22T13:20:36.740 回答
4

看起来您的本地使用逗号“,”作为小数分隔符。要获得“。” 作为小数分隔符,您必须声明:

DecimalFormat dFormat =new DecimalFormat("#.#", new DecimalFormatSymbols(Locale.ENGLISH));
于 2015-09-09T14:59:38.093 回答
4

真正的解决方案是:不要将浮点数用于需要精确计算的任何内容:

  • 如果你在处理货币,不要使用双倍的美元,使用整数的美分。
  • 如果您正在处理数小时的时间并且需要计算一刻钟和 10 分钟的间隔,请使用整数分钟数。

浮点数几乎总是某个实数值的近似值。它们适用于测量和计算物理量(最高精确度)以及统计工件。

将浮点数四舍五入是一种代码味道:这是一种浪费,而且您永远无法真正确定您的代码在所有情况下都能正常工作。

于 2016-05-30T06:26:34.327 回答
3

对于 ' ,' 而不是 ' .' ,您必须更改语言环境。

对于小数位数,使用setMaximumFractionDigits(int newValue).

其余的,请参阅 javadoc

于 2010-04-22T13:20:19.427 回答
2

您不能以这种方式更改double/的内部表示Double

如果您想更改(人类)表示,只需保留它String。因此,不要管它,并在您的演示文稿中Double#valueOf()使用String结果。DecimalFormat#format()如果您想用它进行计算,您可以随时转换回真正的Double使用DecimalFormatand Double#valueOf()

顺便说一句,根据您的抱怨,我正试图在我的双精度值的小数分隔符后去掉不必要的符号您知道浮点数的内部结构吗?闻起来有点像您在表示层中使用了未格式化的双精度,并且您没有意识到使用普通 UI 您可以使用它们来呈现它们DecimalFormat而无需转换回Double.

于 2010-04-22T13:12:02.757 回答
2

与此有些相关,但不是问题的答案:尝试切换到 BigDecimal 而不是双精度浮点数。我在比较这些类型时遇到了很多问题,现在我很乐意使用 BigDecimal。

于 2010-04-22T20:46:21.453 回答
-1

我的代码功能:

 private static double arrondi(double number){
         DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance();
         symbols.setDecimalSeparator('.');
         DecimalFormat format = new DecimalFormat("#.#####", symbols);
         return Double.valueOf(format.format(number));
     }
于 2017-04-07T14:56:24.433 回答