Java 数据格式化&小数点后保留指定位数

Posted ZSYL

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 数据格式化&小数点后保留指定位数相关的知识,希望对你有一定的参考价值。

DecimalFormat

使用 DecimalFormat,但是只能保留指定位数.

DecimalFormat d = new DecimalFormat("0.000");
double x = 3.45125;
System.out.println(d.format(x));  // 3.451

参考上篇博客 详解数字格式化

NumberFormat

public static String format(double value) {
	 // 获取实例对象
     NumberFormat nf = NumberFormat.getNumberInstance();
     nf.setMaximumFractionDigits(2);
     /*
      * setMinimumFractionDigits设置成2
      * 
      * 如果不这么做,那么当value的值是100.00的时候返回100
      * 
      * 而不是100.00
      */
     nf.setMinimumFractionDigits(2);
     nf.setRoundingMode(RoundingMode.HALF_UP);
     /*
      * 如果想输出的格式用逗号隔开,可以设置成true
      */
     nf.setGroupingUsed(false);
     return nf.format(value);
}

Formatter

java.util.Formatter

public static String format(double value) {
 /*
  * %.2f % 表示 小数点前任意位数 2 表示两位小数 格式后的结果为 f 表示浮点型
  */
 return new Formatter().format("%.2f", value).toString();
}

String.format

String.format 作为文本处理工具,为我们提供强大而丰富的字符串格式化功能。

常见使用方式

public static String format5(double value) {
      return String.format("%.2f", value).toString();
}

占位符格式为:
%[index$][标识]*[最小宽度][.精度]转换符

可用标识符

  1. -:在最小宽度内左对齐,不可以与0标识一起使用。
  2. 0:若内容长度不足最小宽度,则在左边用0来填充。
  3. #:对8进制和16进制,8进制前添加一个0,16进制前添加0x。
  4. +:结果总包含一个+或-号。
  5. 空格:正数前加空格,负数前加-号。
  6. ,:只用与十进制,每3位数字间用,分隔。
  7. (:若结果为负数,则用括号括住,且不显示符号。

可用转换符

b,布尔类型,只要实参为非false的布尔类型,均格式化为字符串true,否则为字符串false。
n,平台独立的换行符, 也可通过System.getProperty(“line.separator”)获取。
f,浮点数型(十进制)。显示9位有效数字,且会进行四舍五入。如99.99。
a,浮点数型(十六进制)。
e,指数类型。如 9.38e+5。
g,浮点数型(比%f,%a 长度短些,显示6位有效数字,且会进行四舍五入)

实例展示

// 测试代码
double num = 123.456789;
System.out.print(String.format("%f %n", num));  // %f:默认显示9位有效数字,且会进行四舍五入。%n:默认换行,123.456790
System.out.print(String.format("%a %n", num)); // %a:浮点数型(十六进制),0x1.edd3c0bb46929p6
System.out.print(String.format("%g %n", num)); // %g:浮点数型(比%f,%a长度短些,显示6位有效数字,且会进行四舍五入),123.457

// 保留小数点后位
System.out.println(String.format("%.2f", num));  // 123.46

// 左对齐
int n = 3;
// 6位右对齐,不足六位补0
System.out.println(String.format("%06d", n));  // 000003

// 6位右对齐,不足六位补空格
System.out.println(String.format("%6d", n));  //      3

// 6位左对齐,不足六位补空格
System.out.println(String.format("%-6d", n)); // 3

结果如下
在这里插入图片描述

printf()

C语言printf 函数使用很方便,很高兴Java中也可以使用 printf 的格式:
System.out.printf();
具体使用格式与 String.format() 方法一样,请参考上面。

double num = 20.45628;
// 保留两位小数,%n 换行
System.out.printf("%.2f %n", num);  // 20.46
int n = 6;
// 右对齐5位
System.out.printf("%5d %n", n);
// 左对齐5位
System.out.printf("%-5d %n", n);

在这里插入图片描述

BigDecimal

A BigDecimal由任意精度整数未缩放值和32位整数比例组成。
如果为零或正数,则刻度是小数点右侧的位数。 如果是负数,则数字的非标定值乘以10,以达到等级的否定的幂。
因此, (unscaledValue × 10-scale)代表的BigDecimal值为(unscaledValue × 10-scale) 。
BigDecimal类提供了算术,缩放操作,舍入,比较,散列和格式转换的操作。 toString()方法提供了一个BigDecimal的规范表示。
BigDecimal类使其用户完全控制舍入行为。 如果未指定舍入模式,并且无法表示确切的结果,则抛出异常; 否则,可以通过向操作提供适当的MathContext对象来进行计算,以选择精度和舍入模式。
在这两种情况下,都提供八种舍入方式来控制舍入。 不建议使用此类中的整数字段(如ROUND_HALF_UP )表示舍入模式; 应该使用RoundingMode 枚举的枚举值(如RoundingMode.HALF_UP )。
---- 官方API

BigDecimal 计算和保留小数位是在Java最常用的,也是在财务或者是数据分析中比较重要的方法。

构造方法

Constructor
BigDecimal​(char[] in) 将 BigDecimal的字符数组表示 BigDecimal转换为 BigDecimal ,接受与 BigDecimal(String)构造函数相同的字符序列。  
BigDecimal​(char[] in, int offset, int len) 将 BigDecimal的字符阵列表示 BigDecimal转换为 BigDecimal ,接受与 BigDecimal(String)构造函数相同的字符序列,同时允许指定子数组。  
BigDecimal​(char[] in, int offset, int len, MathContext mc) 将 BigDecimal的字符数组表示 BigDecimal转换为 BigDecimal ,接受与 BigDecimal(String)构造函数相同的字符序列,同时允许根据上下文设置指定子数组并进行舍入。  
BigDecimal​(char[] in, MathContext mc) 将 BigDecimal的字符数组表示 BigDecimal转换为 BigDecimal ,接受与 BigDecimal(String)构造函数相同的字符序列,并根据上下文设置进行舍入。  
BigDecimal​(double val)double转换为 BigDecimal ,它是 double的二进制浮点值的精确十进制表示。  
BigDecimal​(double val, MathContext mc)double转换为 BigDecimal ,根据上下文设置进行舍入。  
BigDecimal​(int val)int翻译成 BigDecimal 。  
BigDecimal​(int val, MathContext mc)int转换为 BigDecimal ,根据上下文设置进行舍入。  
BigDecimal​(long val)long翻译成 BigDecimal 。  
BigDecimal​(long val, MathContext mc)long转换为 BigDecimal ,根据上下文设置进行舍入。  
BigDecimal​(String val) 将 BigDecimal的字符串表示 BigDecimal转换为 BigDecimal 。  
BigDecimal​(String val, MathContext mc) 将 BigDecimal的字符串表示 BigDecimal转换为 BigDecimal ,接受与 BigDecimal(String)构造函数相同的字符串,根据上下文设置进行舍入。  
BigDecimal​(BigInteger val) 将 BigInteger翻译成 BigDecimal 。  
BigDecimal​(BigInteger unscaledVal, int scale) 将 BigInteger值和 int量表翻译成 BigDecimal 。  
BigDecimal​(BigInteger unscaledVal, int scale, MathContext mc) 将 BigInteger值和 int标度转换为 BigDecimal ,根据上下文设置进行舍入。  
BigDecimal​(BigInteger val, MathContext mc) 根据上下文设置将 BigInteger转换为 BigDecimal舍入。  

在这里插入图片描述

舍入方式

BigDecimal.setScale(int newScale, int roundingMode);  // 设置格式化小数位
// 在这个方法中int roundingMode具体的参数如下
BigDecimal.ROUND_UP; //向远离0的方向舍入,进位处理,2.35变为2.4
BigDecimal.ROUND_DOWN;  // 向零方向舍入,3.35变为3.3
BigDecimal.ROUND_CEILING;  // 向正无穷方向舍入
BigDecimal.ROUND_FLOOR;  // 向负无穷方向舍入 
BigDecimal.ROUND_HALF_UP;  // 向(距离)最近的一边舍入,除非两边(的距离)是相等,如果是这样,向上舍入, 1.55保留一位小数结果为1.6 
BigDecimal.ROUND_HALF_DOWN;  // 向(距离)最近的一边舍入,除非两边(的距离)是相等,如果是这样,向下舍入, 例如1.55 保留一位小数结果为1.5 
BigDecimal.ROUND_HALF_EVEN;  // 向(距离)最近的一边舍入,除非两边(的距离)是相等,如果是这样,如果保留位数是奇数,使用ROUND_HALF_UP ,如果是偶数,使用 
BigDecimal.ROUND_UNNECESSARY;  // 计算结果是精确的,不需要舍入模式 

上面的BigDecimal.舍入方式已经过时,改为RoundingMode.舍入方式
如下图:
在这里插入图片描述

具体示例

double n = sc.nextDouble();  // 输入一个数
int k = sc.nextInt();  // 保留 k 位小数
double x = 100.0 * n / 7;
BigDecimal bd = new BigDecimal(x);  // 获取
bd = bd.setScale(k, RoundingMode.HALF_UP);  // 设置保留k位,舍入方式 RoundingMode.HALF_UP:四舍五入

小数点后保留指定n位数

上面谈了这么久,下面引入正题 小数点后保留指定n位数

printf()

经常使用的 System.out.printf(),想着能不能指定保留的位数 k。

比如
保留2位
printf("%.2f")
能不能这样保留 k 位?
printf("%.kf")

System.out.printf("%.(%n)f", k, n); ×
发现不可以
o(╥﹏╥)o

后来发现大佬的C语言题解,有一种方法

#include <stdio.h>
int main()
{
#ifdef LOCAL
	freopen("E:\\input.txt", "r", stdin);
#endif
	char s[] = "%.0f%%\\n";
	int t, n, k;
	scanf("%d", &t);
	while (t--)
	{
		scanf("%d%d", &n, &k);
		printf((s[2] = k + '0', s), 100.0 * n / 7);
	}
	return 0;
}

试着改成Java版

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int t = sc.nextInt();
        char[] s = {'%', '.', '0', 'f', '%', '%', '\\n'};
        while (t-- > 0) {
            int n = sc.nextInt();
            int k = sc.nextInt();
            s[2] = (char)(k + '0');  // '0' ASCII:48
            System.out.printf(new String(s), 100.0 * n / 7);
        }
    }
}

结果如下

在这里插入图片描述
在这里插入图片描述

BigDecimal

参考上面介绍:
BigDecimal.setScale(int newScale, int roundingMode);

double n = sc.nextDouble();
int k = sc.nextInt();  // 保留 k 位
double x = 100.0 * n / 7;
BigDecimal bd = new BigDecimal(x);
bd = bd.setScale(k, RoundingMode.HALF_UP);  // 设置 保留位数,及舍入方式:四舍五入
System.out.println(bd);

结果如下
在这里插入图片描述

特别注意
在练习使用过程中,发现一个特殊的地方:

当浮点数位 0 时,保留 k 位小数,输出结果会有变化:

在这里插入图片描述

这算一个特殊的地方,比赛时试了几次,一直错误,罚时++
o(╥﹏╥)o

后来我们对 0 的情况特殊考虑,就 AK 了!

题目大意

计算 n 门 course 成绩,计算平均成绩,并保留指定位数。

代码如下

int n = sc.nextInt();
    int k = sc.nextInt();
    double sum = 0;
    for (int i = 0; i < n; i++) {
        sum += sc.nextInt();
    }
    if(sum!=0) {
        BigDecimal bd = new BigDecimal(sum);
        BigDecimal N = new BigDecimal(n);
        bd = bd.divide(N, k, RoundingMode.FLOOR);  // 除 N,保留 k位,舍入方式:下舍入
        System.out.println(bd);
    } else {
        System.out.print(0+".");
        for(int i=0;i<k;i++){
            System.out.print(0);
        }
        System.out.println();
    }
}

另外还有一种保留 k位小数的方式:模拟手工除法

联想下:手工如何计算 除法

余数 不足以 整除 除数时,余数乘 10,然后计算循环 k 次,除以 除数。注意:每次保留 商的结果。

代码就不再实现了,o(╥﹏╥)o,两篇博客,整理了几个小时.

感谢博客 Link

感谢 两位队友&宋佬

加油!!!

以上是关于Java 数据格式化&小数点后保留指定位数的主要内容,如果未能解决你的问题,请参考以下文章

c语言如何控制小数位数

c语言如何控制小数位数?

vb保留小数点后2位怎么编写?

科学记数法数字转换/保留数值小数点位数(数字格式化)

js导出excel表如何保留小数点

%f输出的小数,小数点后保留多少位?