在 Java 中,对 double 类型的小数部分进行操作,有几种常见的需求和方法,我将根据不同的需求场景,为你详细解释。

只取小数部分(保留小数点后的数字)
这是最常见的需求,456 取小数部分得到 456。
方法1:使用取模运算符 () - 推荐
这是最直接、最简单的方法,一个数对 1 取模,得到的结果就是它的小数部分。
public class DoubleFractionalPart {
public static void main(String[] args) {
double number1 = 123.456;
double number2 = -78.901;
double number3 = 100.0; // 整数
// 使用 % 运算符
double fractionalPart1 = number1 % 1;
double fractionalPart2 = number2 % 1;
double fractionalPart3 = number3 % 1;
System.out.println(number1 + " 的小数部分是: " + fractionalPart1); // 输出: 123.456 的小数部分是: 0.456
System.out.println(number2 + " 的小数部分是: " + fractionalPart2); // 输出: -78.901 的小数部分是: -0.901
System.out.println(number3 + " 的小数部分是: " + fractionalPart3); // 输出: 100.0 的小数部分是: 0.0
}
}
注意:对于负数, 运算会保留负号,如果你希望小数部分永远是正数,可以取绝对值。
double number = -78.901; double fractionalPart = Math.abs(number % 1); // 使用 Math.abs() 确保结果为正 System.out.println(fractionalPart); // 输出: 0.901
方法2:通过类型转换和减法
这种方法稍微复杂一些,但原理清晰。

- 将
double强制转换为(int),这会直接截断小数部分,只保留整数部分。 - 用原数减去这个整数部分,得到小数部分。
public class DoubleFractionalPartMethod2 {
public static void main(String[] args) {
double number = 123.456;
// 1. 强制转换为 int,截断小数部分
int integerPart = (int) number; // integerPart 变为 123
// 2. 原数减去整数部分
double fractionalPart = number - integerPart;
System.out.println(number + " 的小数部分是: " + fractionalPart); // 输出: 123.456 的小数部分是: 0.456
}
}
注意:此方法对于负数同样需要注意符号问题。(int) -123.456 的结果是 -123,number - integerPart 的结果是 -0.456。
四舍五入到指定位数的小数
这个需求也非常普遍,比如将 456 四舍五入到两位小数,得到 46。
方法1:使用 BigDecimal - 最精确(推荐用于金融计算)
BigDecimal 是处理高精度十进制数的首选,可以完美避免 double 和 float 的精度问题。
import java.math.BigDecimal;
import java.math.RoundingMode;
public class BigDecimalRounding {
public static void main(String[] args) {
double number = 123.456;
int decimalPlaces = 2; // 保留两位小数
// 1. 将 double 转换为 String 再构造 BigDecimal,避免直接 new BigDecimal(double) 的精度问题
BigDecimal bd = new BigDecimal(String.valueOf(number));
// 2. 使用 setScale 方法进行四舍五入
BigDecimal rounded = bd.setScale(decimalPlaces, RoundingMode.HALF_UP);
System.out.println("原始值: " + number);
System.out.println("四舍五入后: " + rounded); // 输出: 四舍五入后: 123.46
}
}
RoundingMode.HALF_UP 是最常用的四舍五入模式。BigDecimal 还提供了其他模式,如 UP (远离零舍入)、DOWN (向零舍入)、CEILING (向正无穷舍入) 等。
方法2:使用 Math.round() - 适用于整数位小数
Math.round() 会返回一个 long 或 int,所以它适用于四舍五入到整数位,如果要保留小数位,需要一些技巧。
public class MathRoundRounding {
public static void main(String[] args) {
double number = 123.456;
int decimalPlaces = 2;
// 核心思路:先将小数点向右移动指定位数,四舍五入,再移回来
// Math.pow(10, decimalPlaces) 得到 10的decimalPlaces次方
double factor = Math.pow(10, decimalPlaces);
// 1. 乘以因子
double temp = number * factor; // 123.456 * 100 = 12345.6
// 2. 四舍五入
long roundedLong = Math.round(temp); // Math.round(12345.6) -> 12346
// 3. 除以因子
double result = (double) roundedLong / factor; // 12346.0 / 100 = 123.46
System.out.println("原始值: " + number);
System.out.println("四舍五入后: " + result); // 输出: 四舍五入后: 123.46
}
}
注意:Math.round() 本质上是 +0.5 然后向下取整,所以它存在 double 的精度问题,对于要求极高的场景,BigDecimal 更可靠。
截断(舍去)指定位数的小数
这个需求是直接砍掉指定位数之后的小数,不进行四舍五入。
方法1:使用 BigDecimal - 精确且简单
import java.math.BigDecimal;
import java.math.RoundingMode;
public class BigDecimalTruncating {
public static void main(String[] args) {
double number = 123.456;
int decimalPlaces = 2;
BigDecimal bd = new BigDecimal(String.valueOf(number));
// 使用 RoundingMode.DOWN 来实现截断
BigDecimal truncated = bd.setScale(decimalPlaces, RoundingMode.DOWN);
System.out.println("原始值: " + number);
System.out.println("截断后: " + truncated); // 输出: 截断后: 123.45
}
}
方法2:使用类型转换和乘除法 - 不精确
public class TruncatingMethod2 {
public static void main(String[] args) {
double number = 123.456;
int decimalPlaces = 2;
double factor = Math.pow(10, decimalPlaces);
// 1. 乘以因子
double temp = number * factor; // 123.456 * 100 = 12345.6
// 2. 强制转换为 long (会截断小数部分)
long truncatedLong = (long) temp; // (long) 12345.6 -> 12345
// 3. 除以因子
double result = (double) truncatedLong / factor; // 12345.0 / 100 = 123.45
System.out.println("原始值: " + number);
System.out.println("截断后: " + result); // 输出: 截断后: 123.45
}
}
注意:此方法同样受 double 精度问题的影响,不推荐用于需要精确计算的场景。
总结与建议
| 需求 | 推荐方法 | 优点 | 缺点 |
|---|---|---|---|
| 只取小数部分 | number % 1 |
简单、直接、性能高 | 负数结果为负,需用 Math.abs() 处理 |
| 四舍五入到N位 | BigDecimal.setScale() |
精度极高,功能强大(多种舍入模式) | 代码稍长,需要引入 java.math 包 |
| 截断到N位 | BigDecimal.setScale(..., RoundingMode.DOWN) |
精度极高,代码清晰 | 需要引入 java.math 包 |
核心建议:
- 如果只是简单地获取小数部分,使用 运算符。
- 如果涉及到金融、货币或任何对精度要求苛刻的场景,请务必使用
BigDecimal。 - 避免使用
float和double来表示精确的十进制数值,因为它们是基于二进制的,无法精确表示某些十进制小数(如 0.1)。
