Is there an equivalent forPrecision () in Java?

When porting the algorithm from JavaScript to Java, I ran into the problem that I need a JavaScript replacement forPrecision (). The problem is that I don’t know how small or large numbers will be, so I cannot use a simple NumberFormat with the correct format.

Is there a standard class that offers similar functionality?

EDIT Here's 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 destroy it. For example, toPrecision(12.34567, 3) returns 12.299999999999997

EDIT 2 This version works great for 11 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

+4
source share
6 answers

Use the BigDecimal and setScale() method to set precision

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

Output

 1.235 

Cm.

+12
source

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

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

I use this in dynjs implementation of Number.prototype.toPrecision .

+3
source

Here's a java solution using String.format.

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

. Replace is only needed if you want to emulate javascript where it does not have index pointers. If you just use it for rounding, return the value as

 return Double.parseDouble(s); 

Here is the unit test code:

 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); } 
+2
source

You can use double with

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

prints

 1.235 

or

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

does the same thing.


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

prints

 1.23E7 1.23E-6 

You can use NumberFormat only to display as decimal.

+1
source

It finally works ...

 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; } 
+1
source
  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)); } } 

. ## represents what decimal places you want. Hope this meets your requirements.

0
source

All Articles