Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there an equivalent for toPrecision() in Java?

Tags:

java

In porting an algorithm from JavaScript to Java, I've run into the problem that I need a replacement for JavaScript's toPrecision(). The problem is that I don't have a clue how small or large the numbers will be, so I can't use a simple NumberFormat with the right format.

Is there a standard class that offers a similar functionality?

EDIT Here is what I came up with:

   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;
    }

In principle, it does the right thing, but rounding errors completely ruin it. For example, toPrecision(12.34567, 3) returns 12.299999999999997

EDIT 2 This version works perfectly for 11 out of 12 test cases...

   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;
    }

But toPrecision(0.00001234567, 3) still returns 1.2299999999999999E-5 instead of 1.23E-5

like image 654
Erich Kitzmueller Avatar asked Dec 01 '22 23:12

Erich Kitzmueller


2 Answers

Use BigDecimal and setScale() method to set the precision

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

Output

1.235

See

  • IDEone demo
like image 188
jmj Avatar answered Dec 07 '22 23:12

jmj


The simplest solution I came up with for this uses a combination of java.math.BigDecimal and java.math.MathContext like so.

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

I'm using this in the dynjs implementation of Number.prototype.toPrecision.

like image 41
lanceball Avatar answered Dec 08 '22 00:12

lanceball