1. Overview
1.概述
In this tutorial, we’ll look at a range of options in Java for truncating a double to two decimal places. We’ll see methods that leave us with a String and options for returning Numbers as well.
在本教程中,我们将了解 Java 中用于将 double 截断到小数点后两位的一系列选项。我们将看到为我们留下 String 的方法,以及返回 Numbers 的选项。
2. Using Math.floor() and Math.ceil() Rounding
2.使用 Math.floor() 和 Math.ceil() 四舍五入
The first method we’ll examine is using the Math class to remove extra decimal places. To truncate a positive number to two decimal places, we first multiply our double by 100, moving all the numbers we want to keep in front of the decimal place. Next, we use Math.floor() to round down, removing everything after the decimal place. Finally, we divide by 100 to undo the previous multiplication:
我们要研究的第一种方法是使用 Math 类删除多余的小数位数。要将一个正数截断为小数点后两位数,我们首先将 double 乘以 100,移动小数点前所有需要保留的数字。接着,我们使用 Math.floor() 向下舍入,删除小数点后的所有数字。最后,我们用 100 除以前面的乘法:
@Test
void givenADouble_whenUsingMath_truncateToTwoDecimalPlaces(){
double positive = 1.55555555;
double truncated = Math.floor(positive * 100) / 100;
assertEquals("1.55", String.valueOf(truncated));
double negative = -1.55555555;
double negativeTruncated = Math.ceil(negative * 100) / 100;
assertEquals("-1.55", String.valueOf(negativeTruncated));
}
The process is almost identical for a negative number, but instead of Math.floor(), we use Math.ceil() to round up. We could’ve added extra code to detect if the double is negative or positive and automatically use the correct method if we wanted.
负数的处理过程几乎相同,但我们使用 Math.ceil() 而不是 Math.floor() 来四舍五入。如果我们愿意,可以添加额外的代码来检测 double 是负数还是正数,并自动使用正确的方法。
For removing more or less decimal places, we’d add or remove zeros to the number we multiplied and divided by. For example, to keep three decimal places, we’d multiply and divide by 1000. This method is useful if we need to keep our double as a double and not end up converting it to a String.
为了去掉更多或更少的小数位,我们要在乘除的数字上加上或去掉零。例如,要保留小数点后三位,我们就要乘以和除以 1000。如果我们需要将 double 保留为 double 而不是最终转换为 String. 时,这种方法就非常有用。
3. Using String.format()
3.使用 String.format()
Let’s move on to options that are designed for display purposes rather than calculations. We’ll get a String back from these methods but can always convert the result back to a double if needed. The String.format() method takes two arguments. Firstly, the format we want to apply, and secondly, the arguments referenced by the format. To truncate to two decimal places, we’ll use the format String “%.2f”:
下面我们来看看那些用于显示而非计算的选项。我们将从这些方法中获得一个 String 返回值,但如果需要,也可以将结果转换为 double 返回值。String.format() 方法需要两个参数。首先是我们要应用的格式,其次是格式引用的参数。要截断到小数点后两位,我们将使用格式 String “%.2f”:
@Test
void givenADouble_whenUsingStringFormat_truncateToTwoDecimalPlaces() {
double positive = 1.55555555;
String truncated = String.format("%.2f", positive);
assertEquals("1.56", truncated);
double negative = -1.55555555;
String negativeTruncated = String.format("%.2f", negative);
assertEquals("-1.56", negativeTruncated);
}
The ‘f’ at the end of our format String instructs the formatter to produce a decimal format, and the ‘.2’ means we want two digits after the decimal place. We could adjust this to truncate to the amount of decimal places required. We can see in the test that the result has, in fact, rounded up rather than truncating, so depending on our requirements, this may not be suitable.
格式 String 末尾的 “f “指示格式器生成十进制格式,而”.2 “表示我们希望在小数点后保留两位数。我们可以将其调整为截断所需的小数位数。我们可以在测试中看到,结果实际上是四舍五入而不是截断,因此根据我们的要求,这可能并不合适。
4. Creating a String Using NumberFormat
4.使用 NumberFormat 创建字符串</em
NumberFormat is an abstract class designed to let us format any number. Because it’s an abstract class, we need to use getNumberInstance() first to receive an object we can use. Note that this will use our default locale unless we instruct it to do otherwise. We can follow that by using setMaximumFractionDigits() to say how many decimal places we want. Finally, because we want to truncate rather than round, we call setRoundingMode() with the argument RoundingMode.DOWN:
NumberFormat是一个抽象类,旨在让我们格式化任何数字。由于它是一个抽象类,我们需要首先使用 getNumberInstance() 来接收一个可以使用的对象。请注意,除非我们另有指示,否则它将使用默认的本地语言。接着,我们可以使用 setMaximumFractionDigits() 来说明我们想要的小数位数。最后,由于我们想要截断而不是四舍五入,因此我们调用了参数为 RoundingMode.DOWN 的 setRoundingMode() :
@Test
public void givenADouble_whenUsingNumberFormat_truncateToTwoDecimalPlaces(){
NumberFormat nf = NumberFormat.getNumberInstance();
nf.setMaximumFractionDigits(2);
nf.setRoundingMode(RoundingMode.DOWN);
double value = 1.55555555;
String truncated = nf.format(value);
assertEquals("1.55", truncated);
double negativeValue = -1.55555555;
String negativeTruncated = nf.format(negativeValue);
assertEquals("-1.55", negativeTruncated);
}
With our NumberFormat setup, it’s then as easy as calling format() with our double. In our test above, we can see that it performs equally well with positive and negative numbers.
设置好 NumberFormat 后,我们就可以使用 double 调用 format() 了。在上面的测试中,我们可以看到它对正负数的处理同样出色。
5. Creating a String Using DecimalFormat
5.使用 DecimalFormat 创建字符串</em
DecimalFormat is a subclass of NumberFormat specifically designed for decimals. It’s a concrete class, so we can go ahead and make an instance of it directly, passing in our desired pattern to the constructor. We’ll pass in “#.##.” here, the number of hashes after the decimal places indicates how many to keep:
DecimalFormat 是 NumberFormat 的子类,专为小数设计。它是一个具体的类,因此我们可以直接创建它的实例,并将我们所需的模式传递给构造函数。我们将在此处传递 “#.##.”,小数点后的散列数表示要保留多少位小数:
@Test
public void givenADouble_whenUsingDecimalFormat_truncateToTwoDecimalPlaces(){
DecimalFormat df = new DecimalFormat("#.##");
df.setRoundingMode(RoundingMode.DOWN);
double value = 1.55555555;
String truncated = df.format(value);
assertEquals("1.55", truncated);
double negativeValue = -1.55555555;
String negativeTruncated = df.format(negativeValue);
assertEquals("-1.55", negativeTruncated);
}
Like with NumberFormat earlier, we’ve specified the use of RoundingMode.DOWN. We see again that this solution handles positive and negative numbers well, making it useful.
与前面的 NumberFormat 一样,我们指定使用 RoundingMode.DOWN 。我们再次看到,该解决方案可以很好地处理正负数,因此非常有用。
6. Optimum Accuracy With BigDecimal
6.使用 BigDecimal 实现最佳精度
Java’s BigDecimal class is best suited to dealing with truncating decimal places directly while keeping the result as a number we can work with. If it’s possible to use this instead of a double, it may be the best option. We can create a BigInteger by passing our double value into the constructor and directly telling it to keep two decimal places by rounding down at the same time:
Java的BigDecimal类最适合直接处理截断小数位的问题,同时将结果保留为我们可以处理的数字。如果可以用它来代替 double 类,那么它可能是最佳选择。我们可以通过将 double 值传入构造函数来创建 BigInteger ,并直接告诉它通过同时向下舍入来保留两位小数:
@Test
void givenADouble_whenUsingBigDecimal_truncateToTwoDecimalPlaces(){
BigDecimal positive = new BigDecimal(2.555555).setScale(2, RoundingMode.DOWN);
BigDecimal negative = new BigDecimal(-2.555555).setScale(2, RoundingMode.DOWN);
assertEquals("2.55", positive.toString());
assertEquals("-2.55", negative.toString());
}
We’ve cast the results to Strings for the purposes of this test to make it visually clear what the result is. However, we could have gone on to perform further calculations using the truncated outputs if we wanted to.
在本测试中,我们将结果转换为字符串,以便直观地显示结果。不过,如果我们愿意,也可以继续使用截断输出执行进一步计算。
7. Conclusion
7.结论
We’ve looked at five different ways we can truncate a double in Java. We’ve seen that String.format(), NumberFormat, and DecimalFormat are usable if we’re creating something for display purposes as they output Strings. Of course, we can always use Double.parseDouble() to convert our Strings back to doubles. Alternatively, we can either use the Math class or BigDecimal to keep our truncated values as numbers for further calculations.
我们已经了解了在 Java 中截断 double 的五种不同方法。我们已经看到,如果我们要创建用于显示目的的内容,String.format()、NumberFormat 和 DecimalFormat 都是可用的,因为它们输出的是 Strings.当然,我们总是可以使用 Double.parseDouble() 将 Strings 转换回 doubles.或者,我们也可以使用 Math 类或 BigDecimal 将截断值保留为数字,以便进一步计算。
As always, the full code for the examples is available over on GitHub.
与往常一样,这些示例的完整代码可在 GitHub 上获取。