奇数性


看下面代码时候是否能判断参数 i 是奇数?

1public static boolean isOdd(int i){ 
2  return i % 2 == 1; 
3}


答案是:No!看似正确的判断奇数,但是如果 i 是负数,那么它返回值都是 false 造成这种现象的是 => 从思想上固化,认为奇数只在正数范围,故判断负数将报错,在 C++ 中也是,负数取余还是负。在 Java 中取余操作定义产生的后果都满足下面的恒等式:

1//int数值a, 与非零int数值b 都满足下面的等式:
2(a / b) * b + (a % b) == a


从上面就可以看出,当取余操作返回一个非零的结果时,左右操作数具有相同的正负号,所以当取余在处理负数的时候,以及会考虑负号。 而上面的这个问题解决方法就是避免判断符号:

1public static boolean isOdd(int i){ 
2    return i % 2 != 0; 
3}

让结果与 0 比较,很容易避免正负号判断。

思考:在使用取余操作的时候要考虑符号对结果的影响。在运算中尝试使用 0 解决符号问题,在一定程度上避免符号对结果的影响。

浮点数产生的误差

看下面代码会打印出什么样的结果?

1public class Change{ 
2  public static void main(String args[]){ 
3    System.out.println(2.00 - 1.10); 
4  } 
5}

从主观上看,打印的结果必然是 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 类,它主要用于精确小数运算。

1import java.math.BigDecimal; 
2public class Change1{ 
3  public static void main(String args[]){ 
4    System.out.println(new BigDecimal("2.00").subtract(new BigDecimal("1.10"))); 
5  } 
6}


通过上面的代码就能得到一个精确的值。 注:使用 BigDecimal 的时候不要使用 BigDecimal(double d) 的构造方法,在 double 与 double 之间传值的时候依旧会引起精度损失,这是一个严重的问题。BigDecimal 底层采用的就是 int[],使用 String 的时候会将 String 不断取每一位存入 int[],使用 double 的时候同理将数字的每一位存入 int[],但是 double 本身存在误差,导致存入的数据会出现误差,例如 0.1 存入 double 就表示为 0.1000000099999999,因此不使用 double 类型的构造函数。 思考:对于精确要求不高的地方,完全可以使用 float/double,但是对于要求精度的计算,比如货币则一定要使用 int、long、BigDecimal。

java 取余 大数 java取余函数_java取负数