- 论坛徽章:
- 0
|
java解惑学习笔记:1.【奇数性】书中谈到取余操作的符号时用到了:(a / b) * b + (a % b) == a,来说明a % b的符号和a是相同的。例如:a = -5,b=2,a/b = -2, (a / b) * b = -4,所以a % b必然是-1。修正放案: ★ 1.public static boolean isOdd(int i) { return i % 2 != 0; } ★★2. 对i求绝对值后进行取模运算。 ★★3.public static boolean isOdd(int i) { return (i & 1) != 0; } 2.【找零时刻】 public class Change{ public static void main(String args[]){ System.out.println(2.00 - 1.10); } }真没想到会打印出那样的一个结果:0.8999999999999999.晕!真长啊!Double.toString()中描述的规则是:There must be at least one digit to represent the fractional part, and beyond that as many, but only as many, more digits as are needed to uniquely distinguish the argument value from adjacent values of type float. That is, suppose that x is the exact mathematical value represented by the decimal representation produced by this method for a finite nonzero argument f. Then f must be the float value nearest to x; or, if two float values are equally close to x, then f must be one of them and the least significant bit of the significand of f must be 0.(大意是:至少要用一个数来表达小数部分,而且尽可能多,但是只需能把这个值和它邻接的float型数据区分开就足够了。也就是说,假如x是对于有限非零实参f用这种方式产生的十进制的精确数学表述,f必定是最接近x的float型数据,或者如果两个float值是与x同样的接近(数轴上),f必定是它们中的一个并且f的最少有效位必须是0)瞎扯了一大堆还是没搞明白是什么意思,试试这个double d =2.0;double f = 1.10;double result = d - f;System.out.println(result);打印是仍旧是:0.8999999999999999。原来如此,并不是toString搞得怪,是原本就算错了。并不是所有的小数都可以用二进制浮点数来精确表示的(书上),但是什么样的浮点数数据是java能过正确表示的????SOLUTION:●1.拙劣的解决方案 - 障眼法System.out.printf("%.2f%n",2.00 - 1.10);★★★2.使用某种整数类型,例如int和long(较优)System.out.println((200 - 110) + "cents");★★3.使用执行精确小数运算的BigDecimalimport java.math.BigDecimal;public class Change1{ public static void main(String args[]){ System.out.println(new BigDecimal("2.00"). subtract(new BigDecimal("1.10"))); }}3.【长整除】public class LongDivision{ public static void main(String args[]){ final long MICROS_PER_DAY = 24 * 60 * 60 * 1000 * 1000; final long MILLIS_PER_DAY = 24 * 60 * 60 * 1000; System.out.println(MICROS_PER_DAY/MILLIS_PER_DAY); }}结果是什么? 还用想肯定是1000。OH my god !活见鬼居然是5.java不具有目标确定类型的特性所以24 * 60 * 60 * 1000 * 1000计算的结果先放在一个中间变量中,最后通过windening conversion提升为long型 ,24 * 60 * 60 * 1000 * 1000 =86400000000 而int型数据表示范围是-2147483648~2147483647很明显是溢出了。关键问题是:在编译中使用的中间变量是由计算的数据决定而不是结果的类型(个人看法)。SOLUTION:public class LongDivision{ public static void main(String args[ ]){ final long MICROS_PER_DAY = 24L * 60 * 60 * 1000 * 1000; final long MILLIS_PER_DAY = 24L * 60 * 60 * 1000; System.out.println(MICROS_PER_DAY/MILLIS_PER_DAY); }正如书上描述的溢出是一个沉默的杀手,我们在尽力避免它的发生,没想到还会遇到这样的事。即使用来保存结果的变量已显得足够大,也并不意味着要产生结果的计算具有正确的类型。当你拿不准时,就使用long运算来执行整个计算。(java的这个缺陷也太菜了吧!)
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/28187/showart_241625.html |
|