[Java]保留数值后2位的几种方法

本文探讨了Java中处理浮点数精度问题的多种方法,包括Math.round、BigDecimal.setScale、DecimalFormat.format、String.format和NumberFormat.setMaximumFractionDigits,对比了它们在保留小数位数时的优劣。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

注:

1、以下分析基于JDK1.8.0_74。

2、实验以Double数值为例

 

一、返回double型

(一)Math.round

1、示例

public static void test1() {

   double num = 123.465;

   //double num = 123.4;

   double result = Math.round(num * 100) / 100.0;

   System.out.println("Math.round(),四舍五入:"+result);

   System.out.println();

}

 

2、说明

以上代码,输出结果为:123.47。保留2位小数策略是,先将double类型扩大100倍,然后使用Math.round方法将其四舍五入为long型整数,最后除以100.0,恰好得到2位小数的double类型值。

但是通过这种方式来保留2位小数并不可靠,毕竟返回的是double类型的数值,如果原double数值小数点后少于2位,如123.4,则最终输出的结果123.4而不是123.40。

如果num = -123.465,则最终输出结果为:-123.46

 

3、源码分析

(1)入参float类型,返回int值

public static int round(float a) {

   //……

}

水平有限,对JDK1.8之后的内部逻辑不做分析,参考1.7的源码简单描述一下。如果入参不等于最接近0.5且比0.5小的浮点数值时,把入参加上0.5后向下取整;否则,返回0。简而言之,取小于等于(参数+0.5)的最大整数。源码如下:

public static int round(float a) {

    if (a != 0x1.fffffep-2f) // greatest float value less than 0.5

        return (int)floor(a + 0.5f);

    else

        return 0;

}

 

(2)入参double类型,返回long值

同样,对JDK1.8之后的内部逻辑不做分析,之前版本的处理逻辑同round(float a)方法一样,只是入参为double类型,返回值为long类型。

 

4、延伸 ―― Math.ceil()、Math.floor()

ceil 天花板;

floor 地板。

顾名思义,一个是向上取整,一个是向下取整。

 

 

(二)BigDecimal.setScale

1、示例

public static void test2() {

   double num = 123.465;

   //double num = 123.4;

   BigDecimal b = new BigDecimal(num);

   double result = b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();

   System.out.println("BigDecimal.ROUND_HALF_UP,四舍五入:"+result);

   result = b.setScale(2, BigDecimal.ROUND_HALF_DOWN).doubleValue();

   System.out.println("BigDecimal.ROUND_HALF_DOWN,五舍六入:"+result);

   result = b.setScale(2, BigDecimal.ROUND_UP).doubleValue();

   System.out.println("BigDecimal.ROUND_UP,进位处理(就是直接加1):"+result);

   result = b.setScale(2, BigDecimal.ROUND_DOWN).doubleValue();

   System.out.println("BigDecimal.ROUND_DOWN,直接去掉尾数:"+result);

   System.out.println();

}

 

2、说明

以上代码分4种策略对double浮点数进行处理,保留2位小数:

BigDecimal.ROUND_HALF_UP表示四舍五入,

BigDecimal.ROUND_HALF_DOWN也是五舍六入,

BigDecimal.ROUND_UP表示进位处理(就是直接加1),

BigDecimal.ROUND_DOWN表示直接去掉尾数。

最终返回double类型浮点数,同Math.round方法一样,不能保证输出结果绝对保留2位小数。

注意了,以上提到的ROUND_HALF_UP、ROUND_HALF_DOWN是有可能出现问题的,就比如上面的代码中num = 123.465,理论上使用ROUND_HALF_DOWN时,最终会输出123.46,而实际上输出的是123.47。百思不解,上网查询了解到,有很多童鞋在使用BigDecimal这2个枚举时都遇到过莫名的精度问题。因此,不推荐使用。

 

 

二、返回String型

(一)DecimalFormat.format

1、示例

public static void test3() {

   double num = 123.465;

   DecimalFormat df = new DecimalFormat("#.00");

   String str = df.format(num);

   System.out.println("DecimalFormat,小数部分四舍五入:"+str);

   System.out.println();

}

 

2、说明

使用DecimalFormat. format保留2位小数,在实例化DecimalFormat时会用到‘0’和‘#’,二者的区别如下:

(1)以‘0’作为占位符组成的正则串

整数(或小数)部分的位数比数值的位数多,转换出的转换出的结果,不足的位置补0:

new DecimalFormat("0000.00").format(123.46)  //转换出的结果:0123.46

new DecimalFormat("0.000").format(123.46)  //转换出的结果: 123.460

new DecimalFormat("0000.000").format(123.46)  //转换出的结果:0123.460

正则串整数(或小数)部分的位数比数值的位数少,转换出的转换出的结果,整数部分不改动,小数部分四舍五入:

new DecimalFormat("0.000").format(123.465)  //转换出的结果:123.465

new DecimalFormat("00.00").format(123.465)  //转换出的结果:123.47

new DecimalFormat("0.00").format(123.465)  //转换出的结果:123.47

(2)以‘#’作为占位符组成的正则串

整数(或小数)部分的位数比数值的位数多,转换出的转换出的结果不变:

new DecimalFormat("####.##").format(123.46)  //转换出的结果:123.46

new DecimalFormat("#.###").format(123.46)  //转换出的结果: 123.46

new DecimalFormat("####.###").format(123.46)  //转换出的结果:123.46

正则串整数(或小数)部分的位数比数值的位数少,转换出的转换出的结果,整数部分不改动,小数部分四舍五入:

new DecimalFormat("#.###").format(123.465)  //转换出的结果:123.465

new DecimalFormat("##.##").format(123.465)  //转换出的结果:123.47

new DecimalFormat("#.##").format(123.465)  //转换出的结果:123.47

 

 

(二)String.format

1、示例

public static void test4() {

   double num = 123.465;

   String format = String.format("%.2f", num);

   System.out.println("String.format,保留后两位,能四舍五入:"+format);

   System.out.println();

}

 

2、说明

字符串格式化方法 format(),按照JDK中的解释:使用指定的格式字符串和参数返回格式化的字符串。

其用的占位符如下:

字母

适用参数类型

说明

%a

浮点数

以16进制输出浮点数

%b / %B

任意值

如果参数为 null 则输出 false,否则输出 true

%c / %C

字符或整数

输出对应的 Unicode 字符

%d

整数

对整数进行格式化输出

%e / %E

浮点数

以科学记数法输出浮点数

%f

浮点数

对浮点数进行格式化输出

%g / %G

浮点数

以条件来决定是否以科学记数法方式输出浮点数

%h / %H

任意值

以 16 进制输出参数的 hashCode() 返回值

%o

整数

以8进制输出整数

%s / %S

字符串

对字符串进行格式化输出

%t

日期时间

对日期时间进行格式化输出

%x / %X

整数

以16进制输出整数

%n

换行符

%%

百分号本身

需要注意的是,以上占位符如果是用的大写,转换出来的字母都是大写;如果是小写,则转换出来是原字符串。

 

3、常用示例

(1)显示部分字符

String.format("%.5s", "Hello, world");       // 输出 "Hello"

String.format("%.5s...", "Hello, world");    // 输出 "Hello..."

 

(2)输出逗号分隔数字

String.format("%,d", 1234567);               // 输出 "1,234,567"

 

(3)逗号分隔+小数点后2位浮点数

String.format("%,.2f", 1234567.8989);               // 输出 "1,234,567.90"

 

(4)向左补齐 0 并对齐(仅对数字有效)

String.format("%08d", 123);                // 输出 "00000123"

 

 

(三)NumberFormat. setMaximumFractionDigits

1、示例

public static void test5() {

   double num = 123.465;

   NumberFormat nf = NumberFormat.getNumberInstance();

   nf.setMaximumFractionDigits(2);

   nf.setRoundingMode(RoundingMode.UP);

   System.out.println("RoundingMode.UP,进位处理(就是直接加1),负数先取绝对值进位处理再负数:"+nf.format(num));

   nf.setRoundingMode(RoundingMode.HALF_UP);

   System.out.println("RoundingMode.HALF_UP,四舍五入,负数先取绝对值再四舍五入再负数:"+nf.format(num));

   nf.setRoundingMode(RoundingMode.DOWN);

   System.out.println("RoundingMode.DOWN,直接去掉尾数,负数先取绝对值再五舍六入再负数:"+nf.format(num));

   nf.setRoundingMode(RoundingMode.HALF_DOWN);

   System.out.println("RoundingMode.HALF_DOWN,五舍六入,负数先取绝对值再五舍六入再负数:"+nf.format(num));

}

 

2、说明

RoundingMode.UP:表示进位处理(就是直接加1),负数先取绝对值进位处理再负数

RoundingMode.HALF_UP:表示四舍五入,负数先取绝对值再五舍六入再负数

RoundingMode.DOWN:表示直接去掉尾数,负数先取绝对值去掉尾数再负数

RoundingMode.HALF_DOWN表示五舍六入,负数先取绝对值再五舍六入再负数

在经过上述试验后证明,使用RoundingMode.HALF_DOWN并没有五舍六入而是四舍五入,文档说明和实际处理结果不一致,这点也许和BigDecimal. ROUND_HALF_DOWN一样也是JDK本身的bug,因此不深研,不推荐使用。

 

 

 

 

### 回答1: Java中的double类型默认保留15到17小数,但在进行运算时,结果可能会被截断或舍入到更少的小数数。如果需要控制输出的小数数,可以使用DecimalFormat类或String.format()方法来格式化输出。例如,保留两位小数可以使用以下代码: ``` double num = 1.23456; System.out.println(String.format("%.2f", num)); ``` 输出结果为:1.23 ### 回答2Java中,double类型默认保留15小数。 在Java中,double是一种浮点数数据类型,用于存储小数或具有小数部分的数值。它占用8个字节(64)的空间,可以表示非常大或非常小的数值。 当我们打印或显示一个double类型的数值时,默认情况下会保留15有效数字。这意味着在打印时,最多可以显示15有效数字,包括小数点前的数字和小数点后的数字。当小数点后的数超过15时,可能会出现舍入误差。 例如,当我们使用以下代码打印一个double类型的数值时: double number = 3.14159265358979323846; System.out.println(number); 输出结果将会是:3.141592653589793 这里,输出结果保留了15有效数字,即小数点后的6。如果我们将number赋值为一个更长的数值,比如3.1415926535897932384626433832795028841,同样使用上述代码打印,输出结果依然是:3.141592653589793 因此,double类型默认保留15小数。但需要注意的是,这只是在打印或显示时的默认行为,double类型的变量在进行计算时可能会出现舍入误差,因为不能精确地表示所有的实数。如果需要更高的精度和准确性,可以使用Java中的BigDecimal类来处理。 ### 回答3: Java中,double类型默认保留小数点后15。这是由于Javadouble类型采用IEEE 754标准的64双精度浮点数表示法,其中52用于表示小数部分。根据这个标准,double类型的有效数为15到17,因此默认情况下,Java会将double类型的数值保留小数点后15。 需要注意的是,尽管double类型可以表示较大范围的数值,但由于浮点数的存储方式和运算特性,它在表示和计算精确度上存在一定的限制。在进行浮点数计算时,可能会出现舍入误差和精度损失的情况,因此在需要精确计算的场景下,推荐使用BigDecimal类进行计算。 如果想要控制double类型的输出小数数,可以使用格式化字符串或DecimalFormat类来实现。例如,可以使用String.format方法或System.out.printf方法来指定小数数的格式化输出,也可以使用DecimalFormat类提供的方法来设置小数数和进方式。这样就可以根据具体需求来控制double类型数值的输出精度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值