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

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

是否有提供类似function的标准类?

编辑这是我想出的:

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

使用BigDecimalsetScale()方法设置精度

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

产量

 1.235 

看到

  • IDEone演示

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

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

我在Number.prototype.toPrecision的dynjs 实现中使用它 。

这是一个使用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。 如果您只是将其用于舍入,则将值返回为

 return Double.parseDouble(s); 

这是一些unit testing代码:

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

你可以使用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仅显示为小数。

这最终有效……

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

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