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\n", 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,則要用A\B\C\D\E\F來表示 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; }