Java中的toPrecision()是否有等价物?

时间:2012-08-21 11:38:28

标签: java

在将算法从JavaScript移植到Java时,我遇到了需要替换JavaScript的toPrecision()的问题。问题是我不知道数字的大小有多大,所以我不能使用格式正确的NumberFormat。

是否有提供类似功能的标准类?

EDIT 以下是我提出的建议:

   double toPrecision(double n, double p) {
        if (n==0) return 0;

        double e = Math.floor(Math.log10(Math.abs(n)));
        double f = Math.exp((e-p+1)*Math.log(10));

        return Math.round(n/f)*f;
    }

原则上,它做了正确的事情,但舍入错误完全毁了它。例如, toPrecision(12.34567, 3)返回12.299999999999997

编辑2 这个版本适用于12个测试用例中的11个......

   double toPrecision(double n, double p) {
        if (n==0) return 0;

        double e = Math.floor(Math.log10(Math.abs(n)));
        double f = Math.round(Math.exp((Math.abs(e-p+1))*Math.log(10)));
        if (e-p+1<0) {
            f = 1/f;
        }

        return Math.round(n/f)*f;
    }

toPrecision(0.00001234567, 3)仍然会返回1.2299999999999999E-5而不是1.23E-5

6 个答案:

答案 0 :(得分:12)

使用BigDecimalsetScale()方法设置精度

BigDecimal bd = new BigDecimal("1.23456789");
System.out.println(bd.setScale(3,BigDecimal.ROUND_HALF_UP));

<强>输出

1.235

答案 1 :(得分:3)

我提出的最简单的解决方案是使用java.math.BigDecimaljava.math.MathContext的组合。

String toPrecision(double number, int precision) {
    return new BigDecimal(number, new MathContext(precision)).toString();
}

我在dynjsimplementation Number.prototype.toPrecision中使用此内容。

答案 2 :(得分:2)

这是一个使用String.format的java解决方案。

public static String toPrecision(double d, int digits) {
    s = String.format("%."+((digits>0)?digits:16)+"g",d).replace("e+0","e+").replace("e-0","e-");
    return s;
}

只有在你想要模仿javascript的时候才需要.replace,它在exponents上没有前导零。如果您只是将其用于舍入,则将值返回为

return Double.parseDouble(s);

以下是一些单元测试代码:

public void testToPrecision() {
    String s = NumberFormat.toPrecision(1234567.0,5);
    assertEquals("1.2346e+6",s);
    s = NumberFormat.toPrecision(12.34567,5);
    assertEquals("12.346",s);
    s = NumberFormat.toPrecision(0.1234567,5);
    assertEquals("0.12346",s);
    s = NumberFormat.toPrecision(0.1234567e20,5);
    assertEquals("1.2346e+19",s);
    s = NumberFormat.toPrecision(-0.1234567e-8,5);
    assertEquals("-1.2346e-9",s);
    s = NumberFormat.toPrecision(1.0/3.0,5);
    assertEquals("0.33333",s);
    s = NumberFormat.toPrecision(1.0/3.0,0);
    assertEquals("0.3333333333333333",s);
}

答案 3 :(得分:1)

您可以将double

一起使用
double d = 1.23456789;
System.out.println(Math.round(d * 1e3) / 1e3);

打印

1.235

System.out.printf("%.3f%n", d);

也一样。


public static void main(String... args) {
    System.out.println(round3significant(12345678.9));
    System.out.println(round3significant(0.0000012345));
}

public static double round3significant(double d) {
    if (d < 100) {
        double divide = 1;
        while(d < 100) {
            d *= 10;
            divide *= 10;
        }
        return Math.round(d) / divide;
    } else {
        double multi = 1;
        while(d > 1000) {
            d /= 10;
            multi *= 10;
        }
        return Math.round(d) * multi;
    }
}

打印

1.23E7
1.23E-6

您可以使用NumberFormat仅显示为小数。

答案 4 :(得分:1)

这最终有效......

double toPrecision(double n, double p) {
    if (n==0) return 0;

    double e = Math.floor(Math.log10(Math.abs(n)));
    double f = Math.round(Math.exp((Math.abs(e-p+1))*Math.log(10)));

    if (e-p+1<0) {
        return Math.round(n*f)/f;
    }

    return Math.round(n/f)*f;
}

答案 5 :(得分:0)

    import java.text.*;  
Class Decimals
{  
    public static void main(String[] args)
    {  
        float f = 125.069f;  
        DecimalFormat form = new DecimalFormat("#.##");  
        System.out.println(form.format(f));  
    }
}

。##代表你想要的小数位数 我希望这符合你的要求。