代码之家  ›  专栏  ›  技术社区  ›  George

decimalformat和double.valueof()。

  •  13
  • George  · 技术社区  · 14 年前

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

    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 上课?还有其他想法吗?

    10 回复  |  直到 7 年前
        1
  •  76
  •   Tobias Kienzler    11 年前

    通过

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

    你的意思是你想四舍五入到小数点后五位吗?那就用吧

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

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

        2
  •  25
  •   the Tin Man Bryan    9 年前

    问题是十进制格式将值转换为本地化字符串。我猜您的区域设置的默认小数分隔符应该是a' , '.这经常发生在法国或世界其他地方。

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

    DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance();
    symbols.setDecimalSeparator('.');
    DecimalFormat format = new DecimalFormat("#.#####", symbols);
    value = format.parse(format.format(41251.50000000012343));
    
        3
  •  5
  •   Community Egal    7 年前

    格式化字符串使用的事实 . 作为十进制分隔符,而异常则抱怨 , 指向区域设置问题;即,decimalformat使用的区域设置格式与double.valueof预期的格式不同。

    一般来说,您应该构造一个 NumberFormat 基于特定的区域设置。

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

    来自Javadocs的 DecimalFormat :

    要获取特定区域设置(包括默认区域设置)的数字格式,请调用NumberFormat的工厂方法之一,如GetInstance()。一般来说,不要直接调用decimalformat构造函数,因为numberFormat工厂方法可能返回decimalformat以外的子类。

    然而 as BalusC points out 尝试将double格式化为字符串,然后将字符串解析回double,这是非常糟糕的代码味道。我怀疑您正在处理的问题是,您希望得到一个固定精度的十进制数字(如货币金额),但却遇到了问题,因为double是一个浮点数,这意味着许多值(如 0.1 )不能精确地表示为double/float。如果是这种情况,处理固定精度十进制数的正确方法是使用 BigDecimal .

        4
  •  3
  •   Tobias Kienzler    14 年前

    使用 Locale.getDefault() 以获取系统的十进制分隔符,您也可以设置该分隔符。不能同时使用不同的分隔符,因为另一个分隔符通常用作分隔符,分隔符的长度为数千:2.001.000,23<=>2001000.23

        5
  •  3
  •   Vaibhav Barad    9 年前

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

    DecimalFormat dFormat =new DecimalFormat("#.#", new DecimalFormatSymbols(Locale.ENGLISH));
    
        6
  •  2
  •   BalusC    14 年前

    不能更改的内部表示形式 double / Double 那样。

    如果你想改变(人的)表现形式,就保留它。 String . 所以,就这样吧 Double#valueOf() 离开并使用 结果 DecimalFormat#format() 在你的演讲中。如果你想用它来计算,你可以把它转换回真实的 双重的 使用 DecimalFormat 双valueof() .

    顺便问一下,根据你的抱怨 我正试图在我的双精度值的小数分隔符之后去掉不必要的符号。 , are you aware of the internals of floating point numbers ?闻起来有点像您在表示层中使用了未格式化的双精度函数,并且您没有意识到,对于一般的用户界面,您可以使用 破坏者 不需要转换回 双重的 .

        7
  •  2
  •   Joao Coelho    14 年前

    与此有点关联,但不是问题的答案:尝试切换到bigdecimal而不是double和float。我对这些类型的比较有很多问题,现在我很乐意使用bigdecimal。

        8
  •  2
  •   the Tin Man Bryan    9 年前

    对于' , '而不是' . '您必须更改区域设置。

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

    剩下的, see the javadoc .

        9
  •  2
  •   Mark Rotteveel    7 年前

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

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

    浮点数几乎总是一些实值的近似值。它们适用于物理量(最高精度)的测量和计算以及统计伪影。

    把浮点数四舍五入到若干位是一种代码味道:这是浪费,你永远不能真正确定你的代码在所有情况下都能正常工作。

        10
  •  0
  •   Neoray    7 年前

    我的代码功能:

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