课程首页 › 第3部分 › 第46课

第46课 给不起的麦子

第3部分 不辞辛苦 · 循环结构· 知识点:for循环、累乘、溢出

给不起的麦子(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的所有水仙花数并输出,各数字之间用空格隔开。