JAVA案例 第二篇:针对大数值取整数和小数、保留几位小数、特定位数的数值、自幂数

简介:

在前面的章节中,我们自定了一个判断大数值是否为整数的方法,今天我们针对这个方法进行展开论述。

我们可以想象一下:既然能够判断一个数值是否为整数,那么就应该有机会将它的整数部分和小数部分分割开来,也就是我们常说的取整(它同时包含了取小数),在我们初学JAVA时,我们常用的方法是强制转换,或者利用BigDecimal.ROUND语句来进行保留0位小数。今天我们用另一个方法来处理,实现取整(取小数)、特定位数的数值、保留几位小数、以及所有自幂数的输出。这个方法是不涉及精度处理的,也没有强制意味。

一、判断数值是否为整数

在JAVA语言入门课程中,取余、取商是学习JAVA语言的基础知识之一,而我们今天的课程就是利用这个基础知识进行操作。我们先将上一节的代码复制过来研究一下:

	/**
	 * 判断整数
	 * 
	 * @param number
	 * @return
	 */
	private static boolean intNumber(BigDecimal number) {
		// TODO Auto-generated method stub
		if (number.remainder(BigDecimal.ONE).equals(BigDecimal.ZERO))
			return true;
		return false;
	}

这个方法其实是根据数字1的特性来处理的:1能够整除任何整数,换言之,只要是整数,都能够被1整除,也就是说余数为0。同理我们利用数字2的特性可以判断一个数的奇偶性。

二、取整、取小数

小数点是一个特殊的符号,它将一个数值分为整数和小数两个部分,我们读数时,前面是个位数、十位数……,后面是十分位数、百分位数……而没有0位数,这有点类似公元纪年法,有公元前、公元后,而没有公元0年。

	/**
	 * 整数部分、小数部分
	 * 
	 * @param number
	 */
	private static void integerDecimal(BigDecimal number) {
		// TODO Auto-generated method stub
		BigDecimal zhengShu;
		BigDecimal xiaoShu;
		if (intNumber(number)) {
			zhengShu = number.stripTrailingZeros();
			System.out.println(number + "的整数部分为:" + zhengShu);
		} else if (!intNumber(number)) {
			BigDecimal number01 = bigAbsolute(number);
			xiaoShu = number01.remainder(BigDecimal.ONE).stripTrailingZeros();
			zhengShu = number01.subtract(xiaoShu).stripTrailingZeros();
			System.out.println(number + "的整数部分为:" + zhengShu + "、小数部分为:" + xiaoShu);
		}

	}

一个数不能被1整除,那么就有余数,其余数必为小数部分,因此我们可以如此拆分。

stripTrailingZeros(),这是BigDecimal类自带的原生方法,它的目的是去除小数点后尾部无效的0(当然在保留特定位数的小数时可能会用到),同时这个方法也为原数值的精度保留提供了一定的帮助,让数值不会“失真”(比如在进行了一系列复杂的、循环性的计算之后,利用这个方法可以确保结果以“1”的方式输出,而不会出现0.9999999……的情况)。

我们在main(){ }方法中输入几个数字进行测试一下:

		integerDecimal(BigDecimal.ZERO);
		integerDecimal(BigDecimal.ONE);
		integerDecimal(BigDecimal.valueOf(3.2));
		integerDecimal(BigDecimal.valueOf(-3.238));
		integerDecimal(BigDecimal.valueOf(3.238));

它的运行结果为:

0的整数部分为:0
1的整数部分为:1
3.2的整数部分为:3、小数部分为:0.2
-3.238的整数部分为:3、小数部分为:0.238
3.238的整数部分为:3、小数部分为:0.238

为了应付大型数值的取值范围,我在里面自定了一个大型数值绝对值的方法:

	/**
	 * 大型数据的绝对值
	 * 
	 * @param number
	 * @return
	 */
	private static BigDecimal bigAbsolute(BigDecimal number) {
		// TODO Auto-generated method stub
		number = number.compareTo(BigDecimal.ZERO) >= 0 ? number.stripTrailingZeros()
				: BigDecimal.ZERO.subtract(number).stripTrailingZeros();
		return number;
	}

三、整数次幂

幂运算在数学领域应用非常广泛,我们今天单独讨论一下整数次幂,至于小数次幂下次有机会再讲。

我们先来看看下列代码:

	/**
	 * 整数次幂
	 * 
	 * @param number
	 * @return
	 */
	private static BigDecimal integerMi(BigDecimal number, BigDecimal pow) {
		// TODO Auto-generated method stub
		BigDecimal multiply = BigDecimal.ONE;

		if (number.equals(BigDecimal.ZERO) && pow.compareTo(BigDecimal.ZERO) <= 0) {
			// 0 的 0 次幂不存在,这在以后异常章节讲述
		} else if (number.compareTo(BigDecimal.ZERO) != 0 && pow.equals(BigDecimal.ZERO))
			multiply = BigDecimal.ONE; // 任何非 0 数值的 0 次幂 = 1
		else if (pow.compareTo(BigDecimal.ZERO) > 0 && intNumber(pow)) {
			for (BigDecimal count = BigDecimal.ONE; count.compareTo(pow) <= 0; count = count.add(BigDecimal.ONE)) {
				multiply = multiply.multiply(number);
			}
		} else if (pow.compareTo(BigDecimal.ZERO) < 0 && intNumber(pow)) {
			for (BigDecimal count = BigDecimal.valueOf(-1); count.compareTo(pow) >= 0; count = count
					.subtract(BigDecimal.ONE)) {
				multiply = multiply.multiply(number);
			}
			multiply = BigDecimal.ONE.divide(multiply); // 负数次幂可以看成是正数次幂的倒数
		}
		return multiply;
	}

我们之所以没有用Math类中的pow()方法,因为这里涉及到了大型数值,而Math.pow()是针对double型“小型”数值的。

我们在main(){ }方法中输入几个数字进行测试一下:

		System.out.println("(-2) ^ 5 = " + integerMi(BigDecimal.valueOf(-2), BigDecimal.valueOf(5)));
		System.out.println("(-2) ^ (-5) = " + integerMi(BigDecimal.valueOf(-2), BigDecimal.valueOf(-5)));
		System.out.println("0 ^ 5 = " + integerMi(BigDecimal.valueOf(0), BigDecimal.valueOf(5)));
		System.out.println("(-2) ^ 0 = " + integerMi(BigDecimal.valueOf(-2), BigDecimal.valueOf(0)));
		System.out.println("2 ^ 5 = " + integerMi(BigDecimal.valueOf(2), BigDecimal.valueOf(5)));
		System.out.println("10 ^ 5 = " + integerMi(BigDecimal.valueOf(10), BigDecimal.valueOf(5)));
		System.out.println("10 ^ (-5) = " + integerMi(BigDecimal.valueOf(10), BigDecimal.valueOf(-5)));

它的运行结果为:

(-2) ^ 5 = -32
(-2) ^ (-5) = -0.03125
0 ^ 5 = 0
(-2) ^ 0 = 1
2 ^ 5 = 32
10 ^ 5 = 100000
10 ^ (-5) = 0.00001

四、特定位数的数值

特定位数的数值也是运用取余方法进行处理:

	/**
	 * 某个位置上的数字
	 * 
	 * @param number
	 * @param weiShu
	 * @return
	 */
	private static BigDecimal weiNumber(BigDecimal number, BigDecimal weiShu) {
		// TODO Auto-generated method stub
		BigDecimal weiNumber = BigDecimal.ZERO;
		BigDecimal pointDisplaceNumber = BigDecimal.ZERO;

		if (weiShu.compareTo(BigDecimal.ZERO) != 0 && intNumber(weiShu)) {
			number = bigAbsolute(number);
			if (weiShu.compareTo(BigDecimal.ZERO) < 0)
				pointDisplaceNumber = number.divide(integerMi(BigDecimal.TEN, weiShu));
			else if (weiShu.compareTo(BigDecimal.ZERO) > 0)
				pointDisplaceNumber = number.divide(integerMi(BigDecimal.TEN, weiShu.subtract(BigDecimal.ONE)));
			pointDisplaceNumber = pointDisplaceNumber.subtract(pointDisplaceNumber.remainder(BigDecimal.ONE));
			weiNumber = pointDisplaceNumber.remainder(BigDecimal.TEN).stripTrailingZeros();
		}
		return weiNumber;
	}

我们在main(){ }方法中输入相应语句测试一下:

		BigDecimal number = BigDecimal.valueOf(3123.45678);
		System.out.println(number + " 的第 1 位数为:" + weiNumber(number, BigDecimal.valueOf(1)));
		System.out.println(number + " 的第 2 位数为:" + weiNumber(number, BigDecimal.valueOf(2)));
		System.out.println(number + " 的第 -3 位数为:" + weiNumber(number, BigDecimal.valueOf(-3)));
		System.out.println(number + " 的第 -1 位数为:" + weiNumber(number, BigDecimal.valueOf(-1)));
		System.out.println(number + " 的第 -2 位数为:" + weiNumber(number, BigDecimal.valueOf(-2)));
		System.out.println(number + " 的第 -4 位数为:" + weiNumber(number, BigDecimal.valueOf(-4)));

它的运行结果为:

3123.45678 的第 1 位数为:3
3123.45678 的第 2 位数为:2
3123.45678 的第 -3 位数为:6
3123.45678 的第 -1 位数为:4
3123.45678 的第 -2 位数为:5
3123.45678 的第 -4 位数为:7

在这里我们用正整数、负整数表示小数点前后的位数,这样子省去了一定的麻烦。

五、保留几位小数

我们在前面讲到了取整、取小数的例子。那我们可以考虑考虑能否对10的整数次幂进行“取整”、“取余”?

在我们int型数据处理时,曾经用“/ 10”、“% 10”进行商余“分割”。那么在BigDecimal数据处理时,能否利用类似的方法进行小数位数的保留与舍弃(也就是所谓的保留几位小数)?其实是可以的。因为我们已经能够提取特殊位数的数值了。

保留小数我们一般选用两种方法:舍弃式保留、四舍五入式保留。根据小数保留的含义我们输入如下代码:

	/**
	 * 舍弃法保留几位小数
	 * 
	 * @param number
	 * @param weiCount
	 * @return
	 */
	private static BigDecimal discardDecimalPlace(BigDecimal number, BigDecimal weiCount) {
		// TODO Auto-generated method stub
		BigDecimal saveNumber = number.subtract(number.remainder(integerMi(BigDecimal.TEN, weiCount)));
		return saveNumber.stripTrailingZeros();
	}
	/**
	 * 四舍五入保留几位小数
	 * 
	 * @param number
	 * @param weiCount
	 * @return
	 */
	private static BigDecimal fourFiveDecimalPlace(BigDecimal number, BigDecimal weiCount) {
		// TODO Auto-generated method stub
		BigDecimal saveNumber = BigDecimal.ZERO;
		if (weiNumber(number, weiCount.subtract(BigDecimal.ONE)).compareTo(BigDecimal.valueOf(5)) < 0)
			saveNumber = number.subtract(number.remainder(integerMi(BigDecimal.TEN, weiCount)));
		if (weiNumber(number, weiCount.subtract(BigDecimal.ONE)).compareTo(BigDecimal.valueOf(5)) >= 0) {
			saveNumber = number.compareTo(BigDecimal.ZERO) > 0
					? number.subtract(number.remainder(integerMi(BigDecimal.TEN, weiCount)))
							.add(integerMi(BigDecimal.TEN, weiCount))
					: BigDecimal.ZERO.subtract(bigAbsolute(number)
							.subtract(bigAbsolute(number).remainder(integerMi(BigDecimal.TEN, weiCount)))
							.add(integerMi(BigDecimal.TEN, weiCount)));
		}
		return saveNumber.stripTrailingZeros();
	}

我们在main()方法中输入如下代码测试一下:

		System.out.println("123.1235434 舍弃保留 1 位小数:" + discardDecimalPlace(BigDecimal.valueOf(123.1235434), BigDecimal.valueOf(-1)));
		System.out.println("123.1235434 舍弃保留 4 位小数:" + discardDecimalPlace(BigDecimal.valueOf(123.1235434), BigDecimal.valueOf(-4)));
		System.out.println("-123.1235434 舍弃保留 3 位小数:" + discardDecimalPlace(BigDecimal.valueOf(-123.1235434), BigDecimal.valueOf(-3)));
		System.out.println(
				"123.23456 舍弃保留  1 位小数:" + discardDecimalPlace(BigDecimal.valueOf(123.23456), BigDecimal.valueOf(-1)));
		System.out.println(
				"123.23456 舍弃保留  2 位小数:" + discardDecimalPlace(BigDecimal.valueOf(123.23456), BigDecimal.valueOf(-2)));
		System.out.println(
				"123.23456 舍弃保留  3 位小数:" + discardDecimalPlace(BigDecimal.valueOf(123.23456), BigDecimal.valueOf(-3)));
		System.out.println(
				"123.23456 舍弃保留  4 位小数:" + discardDecimalPlace(BigDecimal.valueOf(123.23456), BigDecimal.valueOf(-4)));
		System.out.println(
				"123.23456 舍弃保留  5 位小数:" + discardDecimalPlace(BigDecimal.valueOf(123.23456), BigDecimal.valueOf(-5)));
		System.out.println("-123.23456 舍弃保留  1 位小数:"
				+ discardDecimalPlace(BigDecimal.valueOf(-123.23456), BigDecimal.valueOf(-1)));
		System.out.println("-123.23456 舍弃保留  2 位小数:"
				+ discardDecimalPlace(BigDecimal.valueOf(-123.23456), BigDecimal.valueOf(-2)));
		System.out.println("-123.23456 舍弃保留  3 位小数:"
				+ discardDecimalPlace(BigDecimal.valueOf(-123.23456), BigDecimal.valueOf(-3)));
		System.out.println("-123.23456 舍弃保留  4 位小数:"
				+ discardDecimalPlace(BigDecimal.valueOf(-123.23456), BigDecimal.valueOf(-4)));
		System.out.println("-123.23456 舍弃保留  5 位小数:"
				+ discardDecimalPlace(BigDecimal.valueOf(-123.23456), BigDecimal.valueOf(-5)));
		System.out.println("123.23456 四舍五入保留  1 位小数:"
				+ fourFiveDecimalPlace(BigDecimal.valueOf(123.23456), BigDecimal.valueOf(-1)));
		System.out.println("123.23456 四舍五入保留  2 位小数:"
				+ fourFiveDecimalPlace(BigDecimal.valueOf(123.23456), BigDecimal.valueOf(-2)));
		System.out.println("123.23456 四舍五入保留  3 位小数:"
				+ fourFiveDecimalPlace(BigDecimal.valueOf(123.23456), BigDecimal.valueOf(-3)));
		System.out.println("123.23456 四舍五入保留  4 位小数:"
				+ fourFiveDecimalPlace(BigDecimal.valueOf(123.23456), BigDecimal.valueOf(-4)));
		System.out.println("123.23456 四舍五入保留  5 位小数:"
				+ fourFiveDecimalPlace(BigDecimal.valueOf(123.23456), BigDecimal.valueOf(-5)));
		System.out.println("-123.23456 四舍五入保留  1 位小数:"
				+ fourFiveDecimalPlace(BigDecimal.valueOf(-123.23456), BigDecimal.valueOf(-1)));
		System.out.println("-123.23456 四舍五入保留  2 位小数:"
				+ fourFiveDecimalPlace(BigDecimal.valueOf(-123.23456), BigDecimal.valueOf(-2)));
		System.out.println("-123.23456 四舍五入保留  3 位小数:"
				+ fourFiveDecimalPlace(BigDecimal.valueOf(-123.23456), BigDecimal.valueOf(-3)));
		System.out.println("-123.23456 四舍五入保留  4 位小数:"
				+ fourFiveDecimalPlace(BigDecimal.valueOf(-123.23456), BigDecimal.valueOf(-4)));
		System.out.println("-123.23456 四舍五入保留  5 位小数:"
				+ fourFiveDecimalPlace(BigDecimal.valueOf(-123.23456), BigDecimal.valueOf(-5)));

它的运算结果为:

123.1235434 舍弃保留 1 位小数:123.1
123.1235434 舍弃保留 4 位小数:123.1235
-123.1235434 舍弃保留 3 位小数:-123.123
123.23456 舍弃保留  1 位小数:123.2
123.23456 舍弃保留  2 位小数:123.23
123.23456 舍弃保留  3 位小数:123.234
123.23456 舍弃保留  4 位小数:123.2345
123.23456 舍弃保留  5 位小数:123.23456
-123.23456 舍弃保留  1 位小数:-123.2
-123.23456 舍弃保留  2 位小数:-123.23
-123.23456 舍弃保留  3 位小数:-123.234
-123.23456 舍弃保留  4 位小数:-123.2345
-123.23456 舍弃保留  5 位小数:-123.23456
123.23456 四舍五入保留  1 位小数:123.2
123.23456 四舍五入保留  2 位小数:123.23
123.23456 四舍五入保留  3 位小数:123.235
123.23456 四舍五入保留  4 位小数:123.2346
123.23456 四舍五入保留  5 位小数:123.23456
-123.23456 四舍五入保留  1 位小数:-123.2
-123.23456 四舍五入保留  2 位小数:-123.23
-123.23456 四舍五入保留  3 位小数:-123.235
-123.23456 四舍五入保留  4 位小数:-123.2346
-123.23456 四舍五入保留  5 位小数:-123.23456

六、自幂数

自幂数的特点是一个n位自然数,它的每个位上的数字的n次幂之和等于其本身。

根据自幂数的这一特性我们将用上述方法提取每个位置上的数字,并对其进行n次幂之后进行相加,并将最后的结果与原数值进行比较,如果相同,则为自幂数,否则不是自幂数。

依据此方法我们可以编译出如下代码:

	/**
	 * 判断是否为自幂数
	 * 
	 * @param number
	 * @return
	 */
	private static boolean selfPowerNumber(BigDecimal number) {
		// TODO Auto-generated method stub
		if (number.compareTo(BigDecimal.ZERO) >= 0 && intNumber(number)) {
			BigDecimal sum = BigDecimal.ZERO;

			int length = String.valueOf(number).length();
			for (int count = 1; count <= length; count++)
				sum = sum.add(integerMi(weiNumber(number, BigDecimal.valueOf(count)), BigDecimal.valueOf(length)));
			if (sum.equals(number))
				return true;
		}
		return false;
	}

同时我们再设定一个方法用以输出自幂数:

	/**
	 * 自幂数的输出
	 * 
	 * @param number
	 */
	private static void selfPowerNumberPrint(BigDecimal number) {
		// TODO Auto-generated method stub
		if (selfPowerNumber(number)) {
			System.out.print(number + " = ");
			String stringNumber = String.valueOf(number);
			for (BigDecimal a = BigDecimal.valueOf(stringNumber.length()); a.compareTo(BigDecimal.ONE) >= 0; a = a
					.subtract(BigDecimal.ONE)) {
				BigDecimal weiNumber = weiNumber(number, a);
				if (a.compareTo(BigDecimal.ONE) > 0)
					System.out.print(weiNumber + " ^ " + stringNumber.length() + " + ");
				else if (a.equals(BigDecimal.ONE))
					System.out.print(weiNumber + " ^ " + stringNumber.length());
			}
			System.out.println();
		}
	}

我们在main()方法中输入如下两行代码:

		for (BigDecimal number = BigDecimal.ZERO;; number = number.add(BigDecimal.ONE))
			selfPowerNumberPrint(number);

它的运算结果为:

0 = 0 ^ 1
1 = 1 ^ 1
2 = 2 ^ 1
3 = 3 ^ 1
4 = 4 ^ 1
5 = 5 ^ 1
6 = 6 ^ 1
7 = 7 ^ 1
8 = 8 ^ 1
9 = 9 ^ 1
153 = 1 ^ 3 + 5 ^ 3 + 3 ^ 3
370 = 3 ^ 3 + 7 ^ 3 + 0 ^ 3
371 = 3 ^ 3 + 7 ^ 3 + 1 ^ 3
407 = 4 ^ 3 + 0 ^ 3 + 7 ^ 3
1634 = 1 ^ 4 + 6 ^ 4 + 3 ^ 4 + 4 ^ 4
8208 = 8 ^ 4 + 2 ^ 4 + 0 ^ 4 + 8 ^ 4
9474 = 9 ^ 4 + 4 ^ 4 + 7 ^ 4 + 4 ^ 4
54748 = 5 ^ 5 + 4 ^ 5 + 7 ^ 5 + 4 ^ 5 + 8 ^ 5
92727 = 9 ^ 5 + 2 ^ 5 + 7 ^ 5 + 2 ^ 5 + 7 ^ 5
93084 = 9 ^ 5 + 3 ^ 5 + 0 ^ 5 + 8 ^ 5 + 4 ^ 5
548834 = 5 ^ 6 + 4 ^ 6 + 8 ^ 6 + 8 ^ 6 + 3 ^ 6 + 4 ^ 6
1741725 = 1 ^ 7 + 7 ^ 7 + 4 ^ 7 + 1 ^ 7 + 7 ^ 7 + 2 ^ 7 + 5 ^ 7
4210818 = 4 ^ 7 + 2 ^ 7 + 1 ^ 7 + 0 ^ 7 + 8 ^ 7 + 1 ^ 7 + 8 ^ 7

因为编译时间非常长,因此我在这里只选取了部分数值用以验证。

你可能感兴趣的:(JAVA,编程基础)