您的位置:首页 > 其它

g++和vc6.0环境下 几种常见数据类型的最大范围问题

2015-04-23 12:59 344 查看

g++环境中:

int 占4个字节,也就是32位

所以有符号int 的最大值是2^31-1=2147483647

无符号int 的最大值是2^32-1=4294967295

unsigned == unsigned int

#include<iostream>
#include<cmath>
using namespace std;
int main(){
//cout<<sizeof(unsigned)<<endl;

int i = pow(2,31)-1 ;
cout<<"2^31-1="i<<endl;
unsigned int ui = pow(2,32)-1 ;
cout<<"2^32-1="ui<<endl;
return 0;
}


经过测试发现在g++中,int64 == long == long long,都是占8个字节

8个字节,共8*8=64位,所以按理来说对于

有符号long 最大值应该是2^63-1=9223372036854775807

无符号long 最大值应该是2^64-1=18446744073709551615

但是写到代码里却发现有问题啊

#include<iostream>
#include<cmath>
using namespace std;
int main(){

for(unsigned i =30;i<65;i++)
{
unsigned long r = pow(2,i)-1 ;
cout<<"2 ^ "<<i<<" = "<<r<<endl;
}
return 0;
}
输出:

2 ^ 44 = 17592186044415
2 ^ 45 = 35184372088831
2 ^ 46 = 70368744177663
2 ^ 47 = 140737488355327
2 ^ 48 = 281474976710655
2 ^ 49 = 562949953421311
2 ^ 50 = 1125899906842623
2 ^ 51 = 2251799813685247
2 ^ 52 = 4503599627370495
2 ^ 53 = 9007199254740991
2 ^ 54 = 18014398509481984
2 ^ 55 = 36028797018963968
2 ^ 56 = 72057594037927936
2 ^ 57 = 144115188075855872
2 ^ 58 = 288230376151711744
2 ^ 59 = 576460752303423488
2 ^ 60 = 1152921504606846976
2 ^ 61 = 2305843009213693952
2 ^ 62 = 4611686018427387904
2 ^ 63 = 9223372036854775808
2 ^ 64 = 0
可以看出unsigned long的最大值是2^63=9223372036854775808

而且注意我们输出的结果是pow(2,i)-1,所以按理最后的结果一定是一个奇数,但是从i=54以后明显数据就不对了!这是为什么?!

下面在用有符号的long 试试:

#include<iostream>
#include<cmath>
#include<cstdio>
using namespace std;
int main(){
for(unsigned i =30;i<65;i++)
{
long r = pow(2,i)-1 ;
cout<<"2 ^ "<<i<<" = "<<r<<endl;
}
return 0;
}
输出的结果是这样的:

2 ^ 45 = 35184372088831
2 ^ 46 = 70368744177663
2 ^ 47 = 140737488355327
2 ^ 48 = 281474976710655
2 ^ 49 = 562949953421311
2 ^ 50 = 1125899906842623
2 ^ 51 = 2251799813685247
2 ^ 52 = 4503599627370495
2 ^ 53 = 9007199254740991
2 ^ 54 = 18014398509481984
2 ^ 55 = 36028797018963968
2 ^ 56 = 72057594037927936
2 ^ 57 = 144115188075855872
2 ^ 58 = 288230376151711744
2 ^ 59 = 576460752303423488
2 ^ 60 = 1152921504606846976
2 ^ 61 = 2305843009213693952
2 ^ 62 = 4611686018427387904
2 ^ 63 = -9223372036854775808
2 ^ 64 = -9223372036854775808


可以看出:按理应该可以正确表示出2^63-1的但是结果貌似导致了符号位溢出,而且最后真正正确的结果也只是截止到i=54!

对于ACMer常用的long long 类型,结果也是一样的 !不信大家可以试一下。

然后是在vc6.0环境下:

#include<iostream>
#include<cmath>
using namespace std;
int main(){
//cout<<sizeof(unsigned)<<endl;

int i = pow(2,31)-1 ;
cout<<"2^31-1="<<i<<endl;
unsigned int ui = pow(2,32)-1 ;
cout<<"2^32-1="<<ui<<endl;
return 0;
}


结果正确。

在vc6.0环境下,并没有long long数据类型,使用long long 会报错。

在vc6.0中,long = int 都是占4字节,可以表示32位2进制数。

并且,在vc6.0中,long long = __int64占用8字节,可以表示64位2进制数。

现在看看__int64可以表示的最大数:

#include<iostream>
#include<cmath>
using namespace std;
int main(){
for(int i=30;i<65;i++)
{
__int64 r = pow(2,i)-1;
//cout<<"2 ^ "<<i<<"="<<r<<endl;	//使用cout输出__int64会报错!
printf("2 ^ %d = %I64d\n",i,r);
}
return 0;
}
输出结果:

2 ^ 45 = 35184372088831
2 ^ 46 = 70368744177663
2 ^ 47 = 140737488355327
2 ^ 48 = 281474976710655
2 ^ 49 = 562949953421311
2 ^ 50 = 1125899906842623
2 ^ 51 = 2251799813685247
2 ^ 52 = 4503599627370495
2 ^ 53 = 9007199254740991
2 ^ 54 = 18014398509481984
2 ^ 55 = 36028797018963968
2 ^ 56 = 72057594037927936
2 ^ 57 = 144115188075855872
2 ^ 58 = 288230376151711744
2 ^ 59 = 576460752303423488
2 ^ 60 = 1152921504606846976
2 ^ 61 = 2305843009213693952
2 ^ 62 = 4611686018427387904
2 ^ 63 = -9223372036854775808
2 ^ 64 = -9223372036854775808
可以看出有符号的__int64,在i=63的时候发生符号溢出,并且在i=54以后结果都出现了误差!出现的结果和g++环境中是一样的。

下面是无符号的__int64的输出情况:

#include<iostream>
#include<cmath>
using namespace std;
int main(){
for(int i=30;i<65;i++)
{
unsigned __int64 r = pow(2,i)-1;
//cout<<"2 ^ "<<i<<"="<<r<<endl;	//使用cout输出__int64会报错!
printf("2 ^ %d = %I64u\n",i,r);
}
return 0;
}
输出结果:

2 ^ 45 = 35184372088831
2 ^ 46 = 70368744177663
2 ^ 47 = 140737488355327
2 ^ 48 = 281474976710655
2 ^ 49 = 562949953421311
2 ^ 50 = 1125899906842623
2 ^ 51 = 2251799813685247
2 ^ 52 = 4503599627370495
2 ^ 53 = 9007199254740991
2 ^ 54 = 18014398509481984
2 ^ 55 = 36028797018963968
2 ^ 56 = 72057594037927936
2 ^ 57 = 144115188075855872
2 ^ 58 = 288230376151711744
2 ^ 59 = 576460752303423488
2 ^ 60 = 1152921504606846976
2 ^ 61 = 2305843009213693952
2 ^ 62 = 4611686018427387904
2 ^ 63 = 9223372036854775808
2 ^ 64 = 9223372036854775808
可以看出 unsigned __int64也不能获得正确的结果!

最后,难道真的没有办法计算pow(2,64)吗?

当然可以,就是用double或者float

#include<iostream>
#include<cmath>
using namespace std;
int main(){
for(int i=30;i<65;i++)
{
double d = pow(2,i)-1;
cout<<"2 ^ "<<i<<"="<<d<<endl;
}
return 0;
}
结果:

2 ^ 45=3.51844e+013
2 ^ 46=7.03687e+013
2 ^ 47=1.40737e+014
2 ^ 48=2.81475e+014
2 ^ 49=5.6295e+014
2 ^ 50=1.1259e+015
2 ^ 51=2.2518e+015
2 ^ 52=4.5036e+015
2 ^ 53=9.0072e+015
2 ^ 54=1.80144e+016
2 ^ 55=3.60288e+016
2 ^ 56=7.20576e+016
2 ^ 57=1.44115e+017
2 ^ 58=2.8823e+017
2 ^ 59=5.76461e+017
2 ^ 60=1.15292e+018
2 ^ 61=2.30584e+018
2 ^ 62=4.61169e+018
2 ^ 63=9.22337e+018
2 ^ 64=1.84467e+019


使用double和float可以获得完全相同的结果。

double和float的区别有一下几点:

1.名字不同,double:双精度,float:单精度

2.大小不同,double占8个字节,float占4个字节,所以也意味着double的精度更高,范围更大

详情看这个:点击打开链接

现在有两个问题没解决:

1.为什么long(vc中的__int64)不能计算出正确的结果?例如有符号的2^63-1,无符号的2^64-1

2.为什么在2^54以后结果就出现失真?为什么是54而不是53或者55呢?

如果有知道的,请大牛不吝赐教。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: