简介:
在前面的章节中,我们自定了一个判断大数值是否为整数的方法,今天我们针对这个方法进行展开论述。
我们可以想象一下:既然能够判断一个数值是否为整数,那么就应该有机会将它的整数部分和小数部分分割开来,也就是我们常说的取整(它同时包含了取小数),在我们初学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
因为编译时间非常长,因此我在这里只选取了部分数值用以验证。