注:本文来自粉丝[菜鸟逆袭]投稿
1.奇数性
看下面代码时候是否能判断参数 i 是奇数?
public static boolean isOdd(int i){
return i % 2 == 1;
}
答案是: No!
看似正确的判断奇数, 但是如果 i 是负数, 那么它返回值都是false
造成这种现象的是 => 从思想上固化, 认为奇数只在正数范围, 故判断负数将报错, 在C++中也是, 负数取余还是负.
在Java中取余操作定义产生的后果都满足下面的恒等式:
int数值a, 与非零int数值b 都满足下面的等式:
(a / b) * b + (a % b) == a
从上面就可以看出, 当取余操作返回一个非零的结果时, 左右操作数具有相同的正负号, 所以当取余在处理负数的时候, 以及会考虑负号.
而上面的这个问题, 解决方法就是避免判断符号:
public static boolean isOdd(int i){
return i % 2 != 0;
}
让结果与0比较, 很容易避免正负号判断.思考:
1.在使用取余操作的时候要考虑符号对结果的影响
2.在运算中, 尝试使用0解决符号问题, 在一定程度上避免符号对结果的影响
2.浮点数产生的误差
看下面代码会打印出什么样的结果?
public class Change{
public static void main(String args[]){
System.out.println(2.00 - 1.10);
}
}
从主观上看, 打印的结果必然是0.90, 然后这却是一个主观错误.
对于1.10这个数, 计算机只会使用近似的二进制浮点数表示, 产生精度影响.
从上面的例子中来看, 1,10在计算机中表示为1.099999, 这个1.10并没有在计算机中得到精确的表示.
针对这个精度问题, 我们可能会选择: System.out.printf("%.2f%n", 2.00 - 1.10);解决, 尽管打印出来的是正确答案, 但是依旧会暴露出一个问题: 如果精度控制在2.00 - 1.0010; 那么精度误差依旧会出现.
这里也说明了: 使用printf, 计算机底层依旧是使用二进制的方式来计算, 只不过这种计算提供了更好的近似值而已.
那么应该怎么解决这个问题呢?
首先想到是使用int模拟小数每一位, 然后计算, 最后将结果又转化为小数;
以此想到的就是使用BigDecimal类, 它主要用于精确小数运算.
import java.math.BigDecimal;
public class Change1{
public static void main(String args[]){
System.out.println(new BigDecimal("2.00").subtract(new BigDecimal("1.10")));
}
}
通过上面的代码就能得到一个精确的值.注: 使用BigDecimal的时候, 不要使用BigDecimal(double d)的构造方法, 在double与double之间传值的时候依旧会引起精度损失. 这是一个严重的问题.
BigDecimal底层采用的就是int[], 使用String的时候, 会将String不断取每一位存入int[], 使用double的时候, 同理将数字的每一位存入int[], 但是double本身存在误差, 导致存入的数据会出现误差,例: 0.1存入double就表示为0.1000000099999999, 因此不使用double类型的构造函数思考:
当然对于精确要求不高的地方, 完全可以使用float/double, 但是对于要求精度