for循环中奇怪的重复次数
strange number of repetitions in for loop
我写了这个小程序来计算圆周率。
在尝试使用代码并尝试找到最准确的结果时,我发现我的计算机无法计算结果。它可以在几秒钟内重复 33554430 次,但是如果我将 for 循环增加到 33554431 它没有输出任何东西。
所以33554430是一个特殊号码吗?
public class CalculatePi{
public static void main(String[] args){
float pi=0;
int sign=1;
for(float i=1; i <= 33554430; i+=2){
pi += (sign*(1.0/i));
sign*= -1;
}
pi *= 4;
System.out.println(pi);
}
}
此版本适用于两者。这是导致问题的浮动循环变量:
public static void main(String[] args){
float pi=0;
int sign=1;
for(int i=1; i <= 33554430; i+=2){
pi += (sign*(1.0/(float)i));
sign*= -1;
}
pi *= 4;
System.out.println(pi);
}
可能是因为这个 issue:
The finite nonzero values of any floating-point value set can all be
expressed in the form s · m · 2(e - N + 1), where s is +1 or -1, m is
a positive integer less than 2N, and e is an integer between Emin =
-(2K-1-2) and Emax = 2K-1-1, inclusive, and where N and K are parameters that depend on the value set.
你的循环每次递增 2。
2 * 33554430 = 67108860
2^26 = 67108864
也许Java在32位系统中使用26位尾数和6位指数来存储浮点数?
你得到了无限循环,因为在比较 i <= 33554431
期间,int
值 33554431
是 promoted to a float
值,对于浮点数是 "too precise"并且实际上等于 33554432
。
然后,当您尝试将值增加 +2
时,float
不够精确,无法从值 33554432
增加。为了说明我的观点:
float f = 33554432;
System.out.println(f); //33554432
f += 2;
System.out.println(f); //33554432
所以值 f
由于其精度限制不会增加。如果你将它增加,比如 11
,你会得到 33554444
(而不是 33554443
),因为这是可以用该精度表达的最接近的数字。
So is 33554430 a special number?
有点像,不是 33554430,而是 33554432。浮点数的第一个 "special number" 是 16777217
,这是第一个不能表示为 float
的正整数(等于 16777216
作为浮点数)。因此,如果您将 i
变量递增 1
,这就是您遇到的问题。现在,由于您要递增 2
,因此卡住的数字是 16777216 * 2 = 33554432
。
public class CalculatePi{
public static void main(String[] args){
float pi=0;
int sign=1;
for(float i=1; i <= 33554431; i+=2){
pi += (sign*(1.0/i));
sign*= -1;
if( i > 33554410) System.out.println(i);
}
pi *= 4;
System.out.println(pi);
System.out.println((float)33554431);
System.out.println((float)33554432);
System.out.println((float)33554434);
}
}
你在for循环中比较float和int。当您将 33554431
(它是 int 值)转换为 float 时,您会得到 3.3554432E7
.
这是关于准确度、精确度的。当你 运行:
System.out.println((float)33554431); // -> 3.3554432E7
System.out.println((float)33554432); // -> 3.3554432E7
System.out.println((float)33554434); // -> 3.3554432E7
全部 3 打印 3.3554432E7
,这意味着当你将 33554432 的浮点值增加 2 时,你会得到 3.3554432E7
,完全相同的值,并且你的循环永远 运行s .
我写了这个小程序来计算圆周率。
在尝试使用代码并尝试找到最准确的结果时,我发现我的计算机无法计算结果。它可以在几秒钟内重复 33554430 次,但是如果我将 for 循环增加到 33554431 它没有输出任何东西。
所以33554430是一个特殊号码吗?
public class CalculatePi{
public static void main(String[] args){
float pi=0;
int sign=1;
for(float i=1; i <= 33554430; i+=2){
pi += (sign*(1.0/i));
sign*= -1;
}
pi *= 4;
System.out.println(pi);
}
}
此版本适用于两者。这是导致问题的浮动循环变量:
public static void main(String[] args){
float pi=0;
int sign=1;
for(int i=1; i <= 33554430; i+=2){
pi += (sign*(1.0/(float)i));
sign*= -1;
}
pi *= 4;
System.out.println(pi);
}
可能是因为这个 issue:
The finite nonzero values of any floating-point value set can all be expressed in the form s · m · 2(e - N + 1), where s is +1 or -1, m is a positive integer less than 2N, and e is an integer between Emin = -(2K-1-2) and Emax = 2K-1-1, inclusive, and where N and K are parameters that depend on the value set.
你的循环每次递增 2。
2 * 33554430 = 67108860
2^26 = 67108864
也许Java在32位系统中使用26位尾数和6位指数来存储浮点数?
你得到了无限循环,因为在比较 i <= 33554431
期间,int
值 33554431
是 promoted to a float
值,对于浮点数是 "too precise"并且实际上等于 33554432
。
然后,当您尝试将值增加 +2
时,float
不够精确,无法从值 33554432
增加。为了说明我的观点:
float f = 33554432;
System.out.println(f); //33554432
f += 2;
System.out.println(f); //33554432
所以值 f
由于其精度限制不会增加。如果你将它增加,比如 11
,你会得到 33554444
(而不是 33554443
),因为这是可以用该精度表达的最接近的数字。
So is 33554430 a special number?
有点像,不是 33554430,而是 33554432。浮点数的第一个 "special number" 是 16777217
,这是第一个不能表示为 float
的正整数(等于 16777216
作为浮点数)。因此,如果您将 i
变量递增 1
,这就是您遇到的问题。现在,由于您要递增 2
,因此卡住的数字是 16777216 * 2 = 33554432
。
public class CalculatePi{
public static void main(String[] args){
float pi=0;
int sign=1;
for(float i=1; i <= 33554431; i+=2){
pi += (sign*(1.0/i));
sign*= -1;
if( i > 33554410) System.out.println(i);
}
pi *= 4;
System.out.println(pi);
System.out.println((float)33554431);
System.out.println((float)33554432);
System.out.println((float)33554434);
}
}
你在for循环中比较float和int。当您将 33554431
(它是 int 值)转换为 float 时,您会得到 3.3554432E7
.
这是关于准确度、精确度的。当你 运行:
System.out.println((float)33554431); // -> 3.3554432E7
System.out.println((float)33554432); // -> 3.3554432E7
System.out.println((float)33554434); // -> 3.3554432E7
全部 3 打印 3.3554432E7
,这意味着当你将 33554432 的浮点值增加 2 时,你会得到 3.3554432E7
,完全相同的值,并且你的循环永远 运行s .