40

我有一个双精度值 =1.068879335我想只用两个十进制值(例如 1.07)将其四舍五入。

我试过这样

DecimalFormat df=new DecimalFormat("0.00");
String formate = df.format(value);
double finalValue = Double.parseDouble(formate) ;

这给了我以下异常

java.lang.NumberFormatException: For input string: "1,07"
     at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1224)
     at java.lang.Double.parseDouble(Double.java:510)

有人可以告诉我我的代码有什么问题吗?

最后我需要finalValue =1.07;

4

10 回答 10

83

请注意字符串中的逗号:“1,07”。DecimalFormat使用特定于语言环境的分隔符字符串,而Double.parseDouble()没有。由于您碰巧生活在小数点分隔符为“,”的国家/地区,因此您无法解析您的号码。

但是,您可以使用DecimalFormat它来解析它:

DecimalFormat df=new DecimalFormat("0.00");
String formate = df.format(value); 
double finalValue = (Double)df.parse(formate) ;

但你真的应该这样做:

double finalValue = Math.round( value * 100.0 ) / 100.0;

注意:正如已经指出的那样,如果您不需要精确控制精度,则应该只使用浮点数。(财务计算是何时使用它们的主要示例。)

于 2011-01-25T17:34:40.900 回答
21

直播@Sergey 的解决方案,但使用整数除法。

double value = 23.8764367843;
double rounded = (double) Math.round(value * 100) / 100;
System.out.println(value +" rounded is "+ rounded);

印刷

23.8764367843 rounded is 23.88

编辑:正如 Sergey 指出的那样,将 double*int 和 double*double 相乘以及将 double/int 和 double/double 相除应该没有区别。我找不到结果不同的例子。然而,在 x86/x64 和其他系统上,我相信 JVM 使用了用于混合双精度值的特定机器代码指令。

for (int j = 0; j < 11; j++) {
    long start = System.nanoTime();
    for (double i = 1; i < 1e6; i *= 1.0000001) {
        double rounded = (double) Math.round(i * 100) / 100;
    }
    long time = System.nanoTime() - start;
    System.out.printf("double,int operations %,d%n", time);
}
for (int j = 0; j < 11; j++) {
    long start = System.nanoTime();
    for (double i = 1; i < 1e6; i *= 1.0000001) {
        double rounded = (double) Math.round(i * 100.0) / 100.0;
    }
    long time = System.nanoTime() - start;
    System.out.printf("double,double operations %,d%n", time);
}

印刷

double,int operations 613,552,212
double,int operations 661,823,569
double,int operations 659,398,960
double,int operations 659,343,506
double,int operations 653,851,816
double,int operations 645,317,212
double,int operations 647,765,219
double,int operations 655,101,137
double,int operations 657,407,715
double,int operations 654,858,858
double,int operations 648,702,279
double,double operations 1,178,561,102
double,double operations 1,187,694,386
double,double operations 1,184,338,024
double,double operations 1,178,556,353
double,double operations 1,176,622,937
double,double operations 1,169,324,313
double,double operations 1,173,162,162
double,double operations 1,169,027,348
double,double operations 1,175,080,353
double,double operations 1,182,830,988
double,double operations 1,185,028,544
于 2011-01-25T18:30:08.140 回答
8

问题是您使用本地化格式化程序生成特定于区域设置的小数点,在您的情况下是“,”。但是 Double.parseDouble() 需要非本地化的双重文字。您可以通过使用特定于语言环境的解析方法或将格式化程序的语言环境更改为使用“。”的东西来解决您的问题。作为小数点。或者更好的是,通过使用以下内容来避免不必要的格式化:

double rounded = (double) Math.round(value * 100.0) / 100.0;
于 2011-01-25T17:35:35.907 回答
4

你正在尝试做的事情有一些根本性的错误。二进制浮点值没有小数位。您不能有意义地将 1 舍入到给定的小数位数,因为大多数“舍入”十进制值根本无法表示为二进制分数。这就是为什么一个人永远不应该使用floatdouble代表金钱。

因此,如果您希望结果中有小数位,则该结果必须是 a (您String已经通过 否则,结果不可能是你想要的。DecimalFormatBigDecimalsetScale()

阅读浮点指南了解更多信息。

于 2011-01-25T17:37:37.857 回答
3

试试这个:org.apache.commons.math3.util.Precision.round(double x, int scale)

请参阅: http ://commons.apache.org/proper/commons-math/apidocs/org/apache/commons/math3/util/Precision.html

Apache Commons 数学库主页是: http ://commons.apache.org/proper/commons-math/index.html

该方法的内部实现是:

public static double round(double x, int scale) {
    return round(x, scale, BigDecimal.ROUND_HALF_UP);
}

public static double round(double x, int scale, int roundingMethod) {
    try {
        return (new BigDecimal
               (Double.toString(x))
               .setScale(scale, roundingMethod))
               .doubleValue();
    } catch (NumberFormatException ex) {
        if (Double.isInfinite(x)) {
            return x;
        } else {
            return Double.NaN;
        }
    }
}
于 2014-02-20T05:00:55.527 回答
1

您可以尝试定义一个新的 DecimalFormat 并将其用作新的 double 变量的 Double 结果。

举个例子让你明白我刚才说的。

double decimalnumber = 100.2397;
DecimalFormat dnf = new DecimalFormat( "#,###,###,##0.00" );
double roundednumber = new Double(dnf.format(decimalnumber)).doubleValue();
于 2011-01-25T17:30:25.027 回答
1

这在所要求的方式中是不可能的,因为有些数字不能用 IEEE 浮点数精确表示(例如 1/10 = 0.1 不能表示为 aDoubleFloat)。格式化应始终作为将结果呈现给用户之前的最后一步。

我猜你问是因为你想处理货币价值。没有办法用浮点数可靠地做到这一点,你应该考虑切换到定点算术。这可能意味着以“美分”而不是“美元”进行所有计算。

于 2011-01-25T17:35:06.943 回答
1
double TotalPrice=90.98989898898;

  DecimalFormat format_2Places = new DecimalFormat("0.00");

    TotalPrice = Double.valueOf(format_2Places.format(TotalPrice));
于 2013-09-11T13:12:33.997 回答
0

您可以使用这里的格式,

  public static double getDoubleValue(String value,int digit){
    if(value==null){
        value="0";
     }
    double i=0;
     try {
         DecimalFormat digitformat = new DecimalFormat("#.##");
         digitformat.setMaximumFractionDigits(digit);
        return Double.valueOf(digitformat.format(Double.parseDouble(value)));

    } catch (NumberFormatException numberFormatExp) {
        return i;   
    }
}
于 2013-11-18T12:08:40.237 回答
0

如果您不想使用 DecimalFormat(例如由于其效率)并且想要通用解决方案,您也可以尝试使用缩放舍入的这种方法:

public static double roundToDigits(double value, int digitCount) {
    if (digitCount < 0)
        throw new IllegalArgumentException("Digit count must be positive for rounding!");

    double factor = Math.pow(10, digitCount);
    return (double)(Math.round(value * factor)) / factor;
}
于 2019-04-09T04:23:28.893 回答