【java解惑】int转化为float精度问题

如下代码:

public class Example034 {

	public static void main(String[] args) {
		int count = 0;
		int start = 2000000000;
		for (float f = start; f < start + 64; f++) {
			count++;
		}
		System.out.println(count);
		count = 0;
		System.out.println("将循环控制条件的值加1后……");
		for (float f = start; f < start + 65; f++) {
			count++;
		}
		System.out.println(count);
	}
}

输出结果:

0
将循环控制条件的值加1后……

结果分析:

分析第一次循环,该循环只有在循环控制变量f比(float)(start+64)小的时候才执行。(start+64)初始类型是int,被自动执行从int到float的提升,这种提升是以损失精度为代价的。由于f的初值太大,以至于在对其加上 64,然后将结果转型为 float 时,所产生的数值等于直接将 f 转换成 float 的数值。所以第一次循环并未执行,打印了结果0。但是,第一次循环执行完成打印后,为什么第二次的循环却成为了无限循环,没有任何输出结果呢?

首先我们先了解一下,如何知道两个很大的float是否相等呢?比如2000000000和2000000064。关键是要观察到 2, 000, 000, 000 有 10 个因子都是 2:它是一个 2 乘以 9 个 10,而每个 10 都是 5× 2。(2*(5*2)^9 == 2^10*5^9,2的10次方乘以5的9次方),这意味着 2, 000, 000, 000 的二进制表示是以10 个 0 结尾的。 64 的二进制表示只需要 7 位,所以将 64 加到 2, 000, 000, 000上不会对右边7 位之外的其他位产生影响。 特别是, 从右边数过来的第 8 位仍旧是 0。 提升这个 31 位的 int 到具有 24 位精度的 float 会在第 8 位四舍五入, 从而直接丢弃最右边的 7 位。而最右边的 7 位是2, 000, 000, 000 与 2, 000, 000, 064 的不同之处,因此它们的 float 表示是相同的。(蓝字部分内容表示不确定正确性)

如果按照上述讲解,那么上述代码的第二个循环应该同样不可以执行的。但是,事实上,第二个循环执行了,但是是死循环。这是为什么呢?

总之,不要使用浮点数作为循环索引 ,因为它会导致无法预测的行为。如果你在循环体内 需要一个浮点数,那么请使用 int 或 long 循环索引 ,并将其转换为 float 或 double。在将一个 int 或 long 转换成一个 float 或 double时,你可能会丢失精度,但是至少它不会影响到循环本身。当你使用浮点数时,要使用 double 而不是 float,除非你肯定 float 提供了足够的精度,并且存在强制性的性能需求迫使你使用 float。

时间: 2024-10-07 05:36:21

【java解惑】int转化为float精度问题的相关文章

java中int,float,long,double取值范围,内存泄露

java中int,float,long,double取值范围是多少? 写道 public class TestOutOfBound { public static void main(String[] args) { System.out.println(Integer.MAX_VALUE-(-Integer.MAX_VALUE)); //内存溢出System.out.println(Integer.MAX_VALUE); //2的31次方-1,10个数位,正的20亿左右,用在钱上面不一定够Sy

《Java解惑》读书笔记

 摘选自<Java解惑>一书,之前整理了部分,一直没看完,最近为了督促自己每天读点这本书,决定一天至少更新一个谜题的内容,欢迎讨论. 欢迎关注技术博客http://blog.sina.com.cn/u/1822488043 Java解惑读书笔记 谜题1:奇数性 取余操作的定义: ( a / b ) * b + ( a % b ) = a 其中(a/b)是java运算的结果,也就是a/b是一个整数,比如3/2=1. 所以当取余操作返回一个非零结果的时候,它与左操作数具有相同符号. 请测试你的

【java解惑】java中那些反常识的小知识

一.Q:请为 i == i + 1 ;  提供一个声明使得条件成立.  分析:一个数字永远不会等于它自己加 1对吧!如果这个数字是无穷大的又会怎样呢?Java 强制要求使用IEEE二进制浮点数算术标准IEEE 754,它可以让你用一个 double 或 float 来表示无穷大.无穷大加 1 还是无穷大.如果 i 在声明为无穷大那么i == i + 1 就成立.     A:可以用任何被计算为无穷大的浮点算术表达式来声明 i ,例如double i = 1.0 / 0.0; 不过最好是能够利用标

java解惑之常常忘记的事

java解惑之常常忘记的事 2012-10-17 18:38:57|  分类: JAVA |  标签:基础知识  软件开发  |举报|字号 订阅 针对刚接触java的菜鸟来说,java基础知识都是我们必须认真学习的,但是在工作过几年时间的老鸟来说,有时候也会对java的基础知识产生疑问,对于这种不确定,并且很容易混淆的知识点,java解惑已经为大家进行了很好的总结,现在借用一个作者的总结,进行一下罗列,希望能对你有所帮助. 1. 奇偶判断 不要使用 i % 2 == 1 来判断是否是奇数,因为i

Java解惑三:循环之谜

谜题24 byte是有符号的,范围是-128 - 127.而0x90是int类型.比较的时候,不相等. 如果想让其相等,需要进行类型转换:(byte & 0xff) 或者 (byte)0x99. 谜题25 自增运算符对循环的影响.j = j++,先赋值. 谜题26 Integer.MAX_VALUE加一之后会变成Integer.MIN_VALUE,这对循环会有影响. 可以考虑使用long来表示i变量,或者使用效率更高的i != Integer.MAX_VALUE. 谜题27 (-1 <<

《Java 解惑》笔记(一)

<Java 解惑>里都是一些编程时容易忽略的细节,却也蛮有意思的,所以将里面的内容稍作整理,简略地概括一下: 1.奇数性 在编程的时候经常会遇到要判断传进来的参数是否为奇数,而且容易惯性地认为判断余数是否为1即可,如下代码: public static boolean isOdd ( int i ) { return i % 2 == 1 } 这段程序在四分之一的时间里返回的都是错误的答案 因为在所有的 int 数值中,有一半都是负数,而 isOdd 方法对于对所有负奇数的判断都会失败.在任何

[Java解惑]数值表达式

数值表达式... 2 1.    奇偶判断... 2 2.    小数精确计算... 2 3.    int整数相乘溢出... 3 4.    负的十六进制与八进制字面常量... 3 5.    窄数字类型提升至宽类型时使用符号位扩展还是零扩展... 4 6.    ((byte)0x90 == 0x90)?. 5 7.    三元表达式(?:)... 5 8.    +=复合赋值问题... 6 9.    i =++i;与i=i++;的区别... 7 10.      Integer.MAX_

Java解惑(转)

数值表达式 1. 奇偶判断 不要使用 i % 2 == 1 来判断是否是奇数,因为i为负奇数时不成立,请使用 i % 2 != 0 来判断是否是奇数,或使用 高效式 (i & 1) != 0来判断. 2. 小数精确计算 System.out.println(2.00 -1.10);//0.8999999999999999 上面的计算出的结果不是 0.9,而是一连串的小数.问题在于1.1这个数字不能被精确表示为一个double,因此它被表示为最接近它的double值,该程序从2中减去的就是这个值,

Java中的浮点型(Double&amp;Float)计算问题

在刚刚做完的一个项目中,遇到了double型计算不精确的问题.到网上查找后,问题得到解决.经验共享,在这里总结一下. Java中的浮点数类型float和double不能够进行精确运算.这个问题有时候非常严重.比如,经过double型直接计算,1.4×1.5有时会得出2.0999999999999996的结果,但实际上,应该得到2.10.而且,类似的情况并不仅限于乘法计算. 在有的编程语言中提供了专门的货币类型来处理这种情况,但是Java没有.所以,在商业计算中我们要用:java.math.Big