java 四舍五入到小数点后三位的最快方法是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10022195/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is the fastest way to round to three decimal places?
提问by Error_404
The SO community was right, profiling your code before you ask performance questions seems to make more sense then my approach of randomly guessing :-) I profiled my code(very intensive math) and didn't realize over 70% of my code is apparently in a part I didn't think was a source of slowdown, rounding of decimals.
SO 社区是对的,在您提出性能问题之前分析您的代码似乎比我随机猜测的方法更有意义:-) 我分析了我的代码(非常密集的数学)并且没有意识到超过 70% 的代码显然是在我不认为是放缓的部分原因,四舍五入。
static double roundTwoDecimals(double d) {
DecimalFormat twoDForm = new DecimalFormat("#.###");
return Double.valueOf(twoDForm.format(d));
}
My problem is I get decimal numbers that are normally .01,.02,etc..but sometimes I get something like .070000000001 (I really only care about the 0.07 but floating point precision causes my other formulas that result to fail), I simply want the first 3 decimals to avoid this problem.
我的问题是我得到的十进制数通常是 .01、.02 等......但有时我会得到类似 .070000000001 的结果(我真的只关心 0.07 但浮点精度会导致我的其他公式失败),我只需要前 3 位小数来避免这个问题。
So is there a better/faster way to do this?
那么有没有更好/更快的方法来做到这一点?
回答by Adam Liss
The standard way to round (positive) numbers would be something like this:
舍入(正)数的标准方法是这样的:
double rounded = floor(1000 * doubleVal + 0.5) / 1000;
Example 1: floor(1000 * .1234 + 0.5) / 1000
= floor(123.9)/1000
= 0.123
Example 2: floor(1000 * .5678 + 0.5) / 1000
= floor(568.3)/1000
= 0.568
实施例1:floor(1000 * .1234 + 0.5) / 1000
= floor(123.9)/1000
=0.123
实施例2:floor(1000 * .5678 + 0.5) / 1000
= floor(568.3)/1000
=0.568
But as @nuakh commented, you'll always be plagued by rounding errors to some extent. If you want exactly3 decimal places, your best bet is to convert to thousandths (that is, multiply everything by 1000) and use an integral data type (int
, long
, etc.)
但正如@nuakh 评论的那样,在某种程度上,您总是会受到四舍五入错误的困扰。如果你想准确小数点后3位,最好的办法是转换为千分之一(即,乘以1000的一切),并使用一个完整的数据类型(int
,long
,等。)
In that case, you'd skip the final division by 1000 and use the integral values 123
and 568
for your calculations. If you want the results in the form of percentages, you'd divide by 10 for display:
在这种情况下,你会通过1000跳过最后的分配和使用的积分值123
,并568
为您计算。如果您想要百分比形式的结果,您需要除以 10 以显示:
123 → 12.3%
568 → 56.8%
123 → 12.3%
568 → 56.8%
回答by Peter Lawrey
Using a cast is faster than using floor or round. I suspect a cast is more heavily optimised by the HotSpot compiler.
使用演员比使用地板或圆形更快。我怀疑 HotSpot 编译器对演员表进行了更严格的优化。
public class Main {
public static final int ITERS = 1000 * 1000;
public static void main(String... args) {
for (int i = 0; i < 3; i++) {
perfRoundTo3();
perfCastRoundTo3();
}
}
private static double perfRoundTo3() {
double sum = 0.0;
long start = 0;
for (int i = -20000; i < ITERS; i++) {
if (i == 0) start = System.nanoTime();
sum += roundTo3(i * 1e-4);
}
long time = System.nanoTime() - start;
System.out.printf("Took %,d ns per round%n", time / ITERS);
return sum;
}
private static double perfCastRoundTo3() {
double sum = 0.0;
long start = 0;
for (int i = -20000; i < ITERS; i++) {
if (i == 0) start = System.nanoTime();
sum += castRoundTo3(i * 1e-4);
}
long time = System.nanoTime() - start;
System.out.printf("Took %,d ns per cast round%n", time / ITERS);
return sum;
}
public static double roundTo3(double d) {
return Math.round(d * 1000 + 0.5) / 1000.0;
}
public static double castRoundTo3(double d) {
return (long) (d * 1000 + 0.5) / 1000.0;
}
}
prints
印刷
Took 22 ns per round
Took 9 ns per cast round
Took 23 ns per round
Took 6 ns per cast round
Took 20 ns per round
Took 6 ns per cast round
Note: as of Java 7 floor(x + 0.5) and round(x) don't do quite the same thing as per this issue. Why does Math.round(0.49999999999999994) return 1
注意:从 Java 7 floor(x + 0.5) 和 round(x) 开始,按照这个问题做的事情并不完全相同。为什么 Math.round(0.499999999999999994) 返回 1
This will round correctly to within the representation error. This means that while the result is not exact the decimal e.g. 0.001 is not represented exactly, when you use toString() it will correct for this. Its only when you convert to BigDecimal or perform an arithmetic operation that you will see this representation error.
这将正确舍入到表示错误内。这意味着虽然结果不是精确的小数,例如 0.001 没有精确表示,但当您使用 toString() 时,它将对此进行更正。只有当您转换为 BigDecimal 或执行算术运算时,您才会看到此表示错误。