1、问题
1.1 苹果装箱
小明家摘了123个苹果,10个苹果可以装满1箱,10箱苹果就可以装满1车拉到批发市场去出售了,问这些苹果一共能装满几车,几箱,还剩几个苹果?
聪明的朋友可能直接给出答案是1车2箱,最后剩3个苹果。
计算的过程:
123个 / 10 = 12箱,余3个苹果
12箱 / 10 = 1车,余2箱
当然,有朋友会立即指出,为啥要这么SB的算,123的百位1不就是1车,十位2 = 2箱,个位3 = 3个
没错,这就是123这个数表示的意义。百位表示车的数量,十位表示箱的数量,个位表示剩下苹果个数。
假设我们的苹果每满10个就必须装箱,每满10箱就必须装车卖掉(否则就烂了),而这个装箱装车就是我们所谓的进位。
1.2 银行换钱
小明现在有123个1分硬币,想去银行换成整的,最后可换得1元2毛零3分。
这里同样的,1元即是百位的数,2毛即是十位的数,3分就是位的数,这就是数字说代表的现实意义。
2、位的意义及数学概念
2.1 万能公式
所有的十进制数都可以用一个公式来表示:
指数n = an所在的位数,个位n=0,十位n=1,依次递增
而an = 对应位数上的数值
10 = 十进制
那么就有一个万能公式来描述所有进制的记数:
2.2 问题1.1的另一个思考
123个苹果,如果交给计算机去计算能装满几车,几箱,还剩几个苹果?
这时候计算机不能用眼睛去看出123这个数字说表示的意义了,但发现用1.1的计算过程计算机可以描述出来:
a = num % 10; //a 依次等于个、箱、车 num = num / 10; Loop…
同时可能有的朋友有一种想法:
车的指数n=2,貌似把num / 100 = 1 就是车的数量
但是有2个问题:
- 计算机不知道123的数字的长度,假设我们是23个苹果,再去除100就是得到的商是0,0一般是自动忽略的,故此步是多余计算的
- 如果要求箱的数量,num / 10 = 12,这就不对了
如果求余数也会有类似的问题,但求最后剩下的苹果个数时,余数总是对的:
123 % 10 = 3 个
所以才有每次除10的操作,依次让箱、车的位变为个位,也就是编程中的右移操作,然后再求余就没什么问题了,这时候我们多想,要是10进制也有位移操作符多好啊
2.3 10进制的移位操作
当我们把 num 除 10时(余数丢弃,不处理小数),会有一个神奇的现象:
123 / 10 = 12
12 / 10 = 1
这实际上已经是在进行右移操作了,所以10进制右移即是将其除10(左移即是将其乘10),而其余数即是被移除的最低位的数值
2.4 数学证明(注意不涉及小数计算,余数丢弃)
此时a1变为个位了,下次再继续除10,就会将a1移出了
于是,我们就能利用该方法不断的将数右移,然后移出的余数就是对应位上的数的值了。
3、应用
上面说了一堆公式和理论,没看出有啥实际的用处,而理论是为了实践服务的,那么下面就让我们来看看它如何干活的吧
3.1 计算问题1.1中的苹果装箱问题
void CTestMath::LoadApple(unsigned uNum) { int nSize = 0; unsigned uAppleArray[3] = {0}; while (uNum) { uAppleArray[nSize] = uNum % 10; uNum /= 10; nSize++; } printf("The apples can load to %d car, %d box, left %d apple ", uAppleArray[2], uAppleArray[1], uAppleArray[0]); }
3.2 将一个num以10进制形式的字符输出(和苹果装箱问题类似)
int CTestMath::OutputDecimalNum(unsigned uNum, char* pszNum) { int nSize = 0; while (uNum) { pszNum[nSize] = (uNum % 10) + '0'; uNum /= 10; nSize++; } //因为是从低位开始处理,所以放入pszNum的数是倒置的,需要对调一下 for (int i = 0; i < nSize / 2; i++) { char cTemp = pszNum[i]; pszNum[i] = pszNum[nSize - 1 - i]; pszNum[nSize - 1 - i] = cTemp; } pszNum[nSize] = NULL; return nSize - 1; }
4 16进制
4.1 回到问题1.1,随着小明卖苹果有钱了,新换了一辆大车,能装16箱苹果,同时增大了箱子,每箱能装16个苹果,此时123个苹果能装能装满几车,几箱,还剩几个苹果?
此时我们发现,从123的字面上不能直接给出答案了,怎么办?
采用1.1中类似的计算方法:
123个 / 16 = 7箱,余11个苹果,用16进制记为B
7箱 / 16 = 0箱,余7箱
所以答案是能装满0车,7箱,剩B(11)个苹果,记为数字"7B"
此时我们再来看"7B"这个数,就可以用1.1中的方法看出,十位"7"即为箱数,个位B即为剩余的苹果数,可以预计,百位即为车数,这就是不同进制的数的实际意义。
实际上,在我们的实际生活中,我们也有其他进制的应用,如时钟,秒到分,分到小时,即是60进制的,如要问123456秒等于多少小时,多少分,多少秒?即可用类似的算法解决。
4.2 数学证明
回到我们的万能公式,将其转化为16进制的形式:
此公式依然成立,所以我们能用同样的方法解决16进制中的问题
4.2 将10进制数转化为16进制数形式字符
int CTestMath::DecimaltoHexadecimal(unsigned uNum, char* pszHexNum) { int nSize = 0; char cTemp = 0; while (uNum) { cTemp = (uNum % 16); //如果数值大于9,则要用ABCDEF来表示 if (cTemp > 9) { cTemp += ('A' - 10); } else { cTemp += '0'; } pszHexNum[nSize] = cTemp; uNum /= 16; nSize++; } //因为是从低位开始处理,所以放入pszNum的数是倒置的,需要对调一下 for (int i = 0; i < nSize / 2; i++) { cTemp = pszHexNum[i]; pszHexNum[i] = pszHexNum[nSize - 1 - i]; pszHexNum[nSize - 1 - i] = cTemp; } pszHexNum[nSize] = NULL; return nSize - 1; }