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
使用BigDecimal
和setScale()
方法设置精度
BigDecimal bd = new BigDecimal("1.23456789"); System.out.println(bd.setScale(3,BigDecimal.ROUND_HALF_UP));
产量
1.235
看到
- IDEone演示
我想出的最简单的解决方案是使用java.math.BigDecimal
和java.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)); } }
。##代表你想要的小数位数我希望这符合你的要求。