简体   繁体   English

DecimalFormat 和 Double.valueOf()

[英]DecimalFormat and Double.valueOf()

I'm trying to get rid of unnecessary symbols after decimal seperator of my double value.我试图在我的双精度值的十进制分隔符之后去掉不必要的符号。 I'm doing it this way:我是这样做的:

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

But when I run this code, it throws:但是当我运行这段代码时,它抛出:

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 ...

As I see, Double.valueOf() works great with strings like "11.1" , but it chokes on strings like "11,1" .正如我所看到的, Double.valueOf()对像"11.1"这样的字符串效果很好,但它在像"11,1"这样的字符串上会窒息。 How do I work around this?我该如何解决这个问题? Is there a more elegant way then something like有没有更优雅的方式然后像

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

Is there a way to override the default decimal separator value of DecimalFormat class?有没有办法覆盖DecimalFormat类的默认小数分隔符值? Any other thoughts?还有其他想法吗?

By经过

get rid of unnecessary symbols after decimal seperator of my double value在我的 double 值的十进制分隔符之后去掉不必要的符号

do you actually mean you want to round to eg the 5th decimal?你真的是说你想四舍五入到小数点后第五位吗? Then just use然后只需使用

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

(of course you can also Math.floor(value*1e5)/1e5 if you really want the other digits cut off) (当然你也可以Math.floor(value*1e5)/1e5如果你真的想要其他数字被切断)

edit编辑

Be very careful when using this method (or any rounding of floating points).使用此方法(或任何四舍五入的浮点数)时要非常小心。 It fails for something as simple as 265.335.对于像 265.335 这样简单的东西,它失败了。 The intermediate result of 265.335 * 100 (precision of 2 digits) is 26533.499999999996. 265.335 * 100(2位精度)的中间结果是26533.499999999996。 This means it gets rounded down to 265.33.这意味着它被四舍五入为 265.33。 There simply are inherent problems when converting from floating point numbers to real decimal numbers.从浮点数转换为实十进制数时,存在固有的问题。 See EJP's answer here at https://stackoverflow.com/a/12684082/144578 - How to round a number to n decimal places in Javahttps://stackoverflow.com/a/12684082/144578 上查看 EJP 的回答- 如何在 Java 中将数字四舍五入到 n 个小数位

The problem is that your decimal format converts your value to a localized string.问题是您的十进制格式将您的值转换为本地化字符串。 I'm guessing that your default decimal separator for your locale is with a ' , '.我猜你的语言环境的默认小数点分隔符是带有 ' , ' 的。 This often happens with French locales or other parts of the world.这通常发生在法国地区或世界其他地区。

Basically what you need to do is create your formatted date with the '.'基本上你需要做的是用“.”创建格式化日期。 separator so Double.valueOf can read it.分隔符,所以Double.valueOf可以读取它。 As indicated by the comments, you can use the same format to parse the value as well instead of using Double.valueOf .如注释所示,您也可以使用相同的格式来解析值,而不是使用Double.valueOf

DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance();
symbols.setDecimalSeparator('.');
DecimalFormat format = new DecimalFormat("#.#####", symbols);
value = format.parse(format.format(41251.50000000012343));

The fact that your formatting string uses .您的格式化字符串使用. as the decimal separator while the exception complains of , points to a Locale issue;作为小数点分隔符,而异常抱怨,指向区域设置问题; ie DecimalFormat is using a different Locale to format the number than Double.valueOf expects.即 DecimalFormat 使用不同的区域设置来格式化数字,而不是 Double.valueOf 预期的。

In general, you should construct a NumberFormat based on a specific Locale.通常,您应该根据特定的区域设置构造一个NumberFormat

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

From the JavaDocs of DecimalFormat :来自DecimalFormat的 JavaDocs :

To obtain a NumberFormat for a specific locale, including the default locale, call one of NumberFormat's factory methods, such as getInstance().要获取特定语言环境(包括默认语言环境)的 NumberFormat,请调用 NumberFormat 的工厂方法之一,例如 getInstance()。 In general, do not call the DecimalFormat constructors directly, since the NumberFormat factory methods may return subclasses other than DecimalFormat.通常,不要直接调用 DecimalFormat 构造函数,因为 NumberFormat 工厂方法可能返回 DecimalFormat 以外的子类。

However as BalusC points out , attempting to format a double as a String and then parse the String back to the double is a pretty bad code smell.然而, 正如 BalusC 指出的那样,尝试将 double 格式化为 String 然后将 String 解析回 double 是一种非常糟糕的代码味道。 I would suspect that you are dealing with issues where you expect a fixed-precision decimal number (such as a monetary amount) but are running into issues because double is a floating point number, which means that many values (such as 0.1 ) cannot be expressed precisely as a double/float.我怀疑您正在处理您期望固定精度十进制数(例如货币金额)但遇到问题的问题,因为 double 是浮点数,这意味着许多值(例如0.1 )不能精确地表示为双精度/浮点数。 If this is the case, the correct way to handle a fixed-precision decimal number is to use aBigDecimal .如果是这种情况,处理固定精度十进制数的正确方法是使用BigDecimal

Use Locale.getDefault() to get your system's decimal separator which you can also set.使用Locale.getDefault()获取您也可以设置的系统小数点分隔符。 You can't have two different separators at the same time since the other is then usually used as the separator for thousands: 2.001.000,23 <=> 2,001,000.23您不能同时使用两个不同的分隔符,因为另一个通常用作千位分隔符: 2.001.000,23 <=> 2,001,000.23

The real solution is: don't use floating-point numbers for anything that needs to be counted with precision:真正的解决方案是:不要对任何需要精确计数的东西使用浮点数:

  • If you are dealing with currency, don't use a double number of dollars, use an integer number of cents.如果您处理货币,请不要使用双倍数的美元,而使用整数美分。
  • If you are dealing with hours of time and need to count quarter-hours and 10-minute intervals, use an integer number of minutes.如果您要处理几小时的时间并且需要计算四分之一小时和 10 分钟的间隔,请使用整数分钟。

A floating point number is almost always an approximation of some real value.浮点数几乎总是某个实数值的近似值。 They are suitable for measurements and calculation of physical quantities (top a degree of precision) and for statistical artifacts.它们适用于物理量的测量和计算(最高精确度)和统计工件。

Fooling about with rounding floating point to a number of digits is a code smell: it's wasteful and you can never really be sure that your code will work properly in all cases.将浮点数四舍五入为多个数字是一种代码味道:这是一种浪费,您永远无法真正确定您的代码在所有情况下都能正常工作。

For the ' , ' instead of the ' .对于 ' , ' 而不是 ' . ' , you'd have to change the locale. ' ,您必须更改语言环境。

For the number of decimals, use setMaximumFractionDigits(int newValue) .对于小数位数,请使用setMaximumFractionDigits(int newValue)

For the rest, see the javadoc .其余的, 请参阅 javadoc

looks like your local use a comma "," as a decimal separation.To get the "."看起来你的本地使用逗号“,”作为小数分隔。要得到“。” as a decimal separator, you will have to declare:作为小数分隔符,您必须声明:

DecimalFormat dFormat =new DecimalFormat("#.#", new DecimalFormatSymbols(Locale.ENGLISH));

You can't change the internal representation of double / Double that way.您不能以这种方式更改double / Double的内部表示。

If you want to change the (human) representation, just keep it String .如果您想更改(人类)表示,只需保留它String Thus, leave that Double#valueOf() away and use the String outcome of DecimalFormat#format() in your presentation.因此,不要使用Double#valueOf()并在演示文稿中使用DecimalFormat#format()String结果。 If you ever want to do calculations with it, you can always convert back to a real Double using DecimalFormat and Double#valueOf() .如果您想用它进行计算,您始终可以使用DecimalFormatDouble#valueOf()将其转换回真正的Double

By the way, as per your complain I'm trying to get rid of unnecessary symbols after decimal seperator of my double value , are you aware of the internals of floating point numbers ?顺便说一下,根据你的抱怨,我试图在我的双精度值的十进制分隔符之后去掉不必要的符号你知道浮点数的内部结构吗? It smells a bit like that you're using unformatted doubles in the presentation layer and that you didn't realize that with the average UI you can just present them using DecimalFormat without the need to convert back to Double .听起来有点像您在表示层中使用未格式化的双精度数,并且您没有意识到使用普通 UI 您可以只使用DecimalFormat来表示它们,而无需转换回Double

Somewhat related to this, but not an answer to the question: try switching to BigDecimal instead of doubles and floats.与此有些相关,但不是问题的答案:尝试切换到 BigDecimal 而不是双精度数和浮点数。 I was having a lot of issue with comparisons on those types and now I'm good to go with BigDecimal.我在比较这些类型时遇到了很多问题,现在我很高兴使用 BigDecimal。

My code function :我的代码功能:

 private static double arrondi(double number){
         DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance();
         symbols.setDecimalSeparator('.');
         DecimalFormat format = new DecimalFormat("#.#####", symbols);
         return Double.valueOf(format.format(number));
     }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM