第46课 给不起的麦子
给不起的麦子(for循环、累乘、溢出)
有这样一个很著名的故事,国王要重赏国际象棋的发明者达依尔,国王问:“你想要什么奖励?”达依尔指着国际象棋的棋盘,对国王说:“我只要在棋盘上放麦子,每一小格的麦子都比前一小格多一倍。第一格放1颗,第二格放2颗,第三格放4颗,第四格放8颗,第五格放16颗……按这个方法,我只要这棋盘上64个小格的麦子!”
国王以为要不了多少粮食,随口就答应了。但是还没有放到20格,一袋麦子就空了,后来粮仓空了,就算把全国的粮食都给他,都还不够!
你知道放满这个棋盘要多少颗麦子吗?
给不起的麦子

运行程序:
(1)for(int i=1;i<=64;i++):通过for循环依次向棋盘的64个格子中放入麦子。
(2)sum*=2:后一个格子是前一个格子的两倍。
提出思考
(1)为什么在放第32个的时候出现负数?
int类型能表示的最大正整数为:0111 1111 1111 1111 1111 1111 1111 1111(最高位是符号位,正数符号位为0,负数符号位为1),对应的十进
制数为2^31-1=2147483647。取值范围为-2,147,483,648~2,147,483,647。
(2)能明白数字为什么是2,147,483,647,但是不知道为什么是-2,147,483,648呢?
在C++中,整数类型数值的最大溢出通常会导致结果变为负数的最小值,这是因为C++中整数类型的表示采用的是二进制补码表示法。在这种表示方法中,最高位表示符号位,0表示正数,1表示负数。当一个整数类型的变量值溢出时,其二进制表示的最高位会变为1,在十进制中也就变成了-2,147,483,648,从而将结果解释为负数。
下面用一个简单的示例来说明这个概念。假设我们使用一个8位的有符号整数类型,它的最大值是127(01111111,二进制表示),最小值是-128(10000000,二进制表示)。如果我们将最大值127加1,即发生了溢出,其二进制表示将变为10000000,这个二进制数在有符号整数表示中被解释为-128,而不是128。
(3)最后为什么又成0了呢?
当sum等于负数的最小值时,继续乘以2将导致数值溢出,并且结果会变为0。这是因为在二进制补码表示法中,负数的最小值(即最高位为1,其余位为0)向左移位一次后会变成0。
试试数据类型long long long long

运行程序:

long long的范围是-9223372036854775808~9223372036854775807,与结果相比就差1了,我们让sum减1试试看是否还会溢出。
快看,输出没有溢出边界了。
巩固练习
(1)假设一个8位有符号整数的最大值是127(01111111,二进制表示),最小值是-128(10000000,二进制表示)。如果将127加1,会发生什么?()
A.结果变为0
B.结果变为128
C.结果变为-128
D.结果变为-127
(2)下面哪个数据类型可以用来容纳大整数值,以避免整数溢出?()
A.int
B.float
C.long long
D.double
(3)水仙花数也被称为自恋数、阿姆斯特朗数,是一种特殊的整数。一个n位数如果等于其各位数字的n次幂之和,则被称为水仙花数。例如,153是一个水仙花数,因为1^3+ 5^3 + 3^3=153。
使用一个for循环,找出100~999的所有水仙花数并输出,各数字之间用空格隔开。