本文章原文地址:https://www.cnblogs.com/BobHuang/p/15497977.html,原文體驗更佳
數制在近兩年高考中分別在20年7月、21年1月和21年6月選擇題第4題出現,較為重要。
一、數的進制
進制是一種記數方式,亦稱進位計數法或位值計數法。利用這種記數法,可以使用有限種數字符號來表示所有的數值。任何一種數制都包含兩個基本要素:基和權。基又叫基數,是組成該數制的數碼個數,一般來說,k進制的基數就是k,包含k個數字;權又叫權值,是指每一個數位上的1對應的數值,可以表示為基數的若干次冪。十進制數的基數為10,十進制數234中2的權值是\(10^3\),3的權值是\(10^1\),4的權值是\(10^0\),所以十進制數234還可表示為:\(2×10^2+3×10^1+4×10^0\)
除了生活中常見的10進制,計算機還有二進制、十六進制等,我們通常用一個下標來表示該數的進制(十進制數可以忽略),也可以在該數的最后以字母來表示,見下表。
進位制 | 二進制 | 八進制 | 十進制 | 十六進制 |
---|---|---|---|---|
標識 | B | O | D | H |
二、十進制
我們先來看6785: 3位數的每一位 輸入一個三位數的自然數,然后一次輸出這個數的每位上的數字,並用逗號分隔。
10進制的123為什么代表123呢,\(123=1*100 + 2*10 + 3*1\),即123有1個100,2個10和3個1,也就是逢10進1,10進制中每一位只會出現0~9。
- 求個位最簡單,直接%10即可;
- 求十位呢,123有12個10,但是10個10是百位(10進制中每一位只會出現0~9,不能出現10),所以任意一個數我們//10后再求次個位也就是%10就可以求出十位;
- 求百位也就是有幾個100,直接//100即可。
給定任意一個數,%10得到當前位,//10拋棄當前位,不斷重復下去,即可以得到其每一位。
參考代碼
n=int(input())
# 求出個位
c=n%10
# 求出十位(拋棄個位后再求個位)
b=n//10%10
# 求出百位(拋棄個位和十位后)
a=n//100
print(a,b,c,sep=',')
三、二進制
數據在計算機內部是以二進制方式進行存儲和處理的。計算機的內部有無數個負責開關的半導體元件,0代表開關的斷,1代表開關的合。生活中的二進制有邏輯上的“真”與“假”,黑白圖像中的“黑”與“白”。二進制由德國數學家萊布尼茨發明,到20世紀40年代應用在電子計算機中。二進制是計算機的核心。
二進制數的特點是
- 有兩個基本數碼:0,1。
- 采用逢二進一的進位規則。
二進制用字母B標識,例如\(\rm{1101.01B=1\times2^3+1\times2^2+0\times2^1+1\times2^0+0\times2^{-1}+1\times2^{-2}}\) 。\(2^3,2^2,2^1,2^0,2^{-1},2^{-2}\)是不同位置上的權值。
二進制中的0和1可以認為是有或無,可以嘗試下6831: 蘋果裝箱問題
四、十進制轉二進制
十進制和二進制之間關系
十進制 | 二進制 | 十進制 | 二進制 | |
---|---|---|---|---|
0 | 0 | 8 | 1000 | |
1 | 1 | 9 | 1001 | |
2 | 10 | 10 | 1010 | |
3 | 11 | 11 | 1011 | |
4 | 100 | 12 | 1100 | |
5 | 101 | 13 | 1101 | |
6 | 110 | 14 | 1110 | |
7 | 111 | 15 | 1111 |
十進制數存在和二進制數以上的轉換關系,15以內的我們可以搞定了。若給定十進制數超過15求出其2進制值表示怎么做呢?
因為二進制僅存0和1,所以若可以求出位數,可以直接分別求出每一位是0還是1。十進制正整數n的二進制位數為\(\lfloor \log_2n \rfloor + 1\),\(\lfloor {\quad} \rfloor\)表示向下取整。
參考代碼1
import math
n=int(input())
# num_of_digits 表示位數
num_of_digits = math.floor((math.log2(n))) + 1
# 用對應的權值分別求出0和1,最高位為2^(位數-1),最低位為2^0
for i in range(num_of_digits-1,-1,-1):
# 當前位所對應的權值為2^i
current_digit = n // (2**i)
print(current_digit,end="")
# 求完之后減去當前位影響
n -= current_digit * (2**i)
6882: 十進制轉二進制提供了一種更為簡潔的方法,我們可以將其%2獲得當前位,然后//2拋棄當前位,直到0為止。
100/2 = 50···0
50 / 2 = 25···0
25 / 2 = 12···1
12 / 2 = 6···0
3 / 2 = 1···1
1 / 2 = 0···1
將所得的余數倒過來即得到答案1100100,如下圖所示。
直到0為止也就是while語句,我們可以寫出如下代碼:
參考代碼2
n=int(input())
# n_base_2 代表2進制數,初始為空
n_base_2 = ''
# 直到n為0結束
while n:
# n%2獲得當前位,為int,需要轉換為str字符串
# 先求出低位,最后求得高位。所以是當前位+之前求的
n_base_2 = str(n%2) + n_base_2
# 拋棄當前位
n = n // 2
print(n_base_2)
先求出的是低位,最后是高位,也就是先進后出的關系。滿足選修一第三章“棧”的性質,所以也可以用棧去完成。
參考代碼3
st = [-1]*100
# top代表頂端的位置,初始沒有值,所以頂端不存在為-1
top = -1
n = int(input())
# 直到0結束
while n:
# 要放在棧頂,棧元素個數+1
top = top+1
# 當前位進棧
st[top] = n % 2
# 拋棄當前位
n = n//2
# 按照棧從后往前輸出
while top >= 0:
print(st[top], end="")
top = top-1
Python的format函數非常強大,存在更簡單的寫法。
參考代碼4
n=int(input())
print(format(n,'b'))
五、二進制轉十進制
6883: 二進制轉十進制 給定二進制數,讓我們轉10進制。
第1位索引 i 為0,其對應為\(2^{位數-1}\),也就是\(2^{n-1-i}\),每一位依次累加即可。
參考代碼1
s = input()
# n存儲結果
n = 0
# 求出長度
l = len(s)
# 對每一位分別進行處理
for i in range(l):
# s[i]為當前位,類型為str,注意轉換
n += int(s[i])*2**(l-1-i)
print(n)
當然還存在其他做法,我們從前到后依次處理,每次都將上次得到的結果乘2+當前位,這樣正好每一位乘上的位權是正確的。
參考代碼2
s = input()
# n存儲十進制數
n = 0
# 對每一位分別進行處理
# 由於和索引無關,可以直接遍歷字符串
for i in s:
# 把上次結果*2+當前位
n = n * 2 + int(i)
print(n)
Python的int函數自帶進制的處理,直接利用代碼很短
參考代碼4
n = int(input(),2)
print(n)
六、十六進制
二進制數在實際使用中,由於位數太長,不便於書寫和記憶,所以人們常采用十六進制數來表示。
十六進制數的特點是
- 由十六個基本數碼組成,即0,1,2,…,9,A,B,C,D,E,F
- 采用逢十六進一的進位規則。
十六進制用字母H標識,\(\rm{B574H=11×16^3+5×16^2+7×16^1+4×16^0}\)。與二進制相類似,\(16^3,16^2,16^1,16^0\)是不同位置上的權值。
七、十六進制和其他進制轉換
十進制和十六進制之間關系
十進制 | 十六進制 | 十進制 | 十六進制 | |
---|---|---|---|---|
0 | 0 | 8 | 8 | |
1 | 1 | 9 | 9 | |
2 | 2 | 10 | A | |
3 | 3 | 11 | B | |
4 | 4 | 12 | C | |
5 | 5 | 13 | D | |
6 | 6 | 14 | E | |
7 | 7 | 15 | F |
7031: 十進制轉十六進制。求10進制數的每一位我們用了%10得到當前位,//10拋棄當前當前位,不斷進行直到0為止。十進制轉二進制也是這樣,十六進制當然也同理,換為16就可以了,不過10~15還是需要我們特殊處理下。
參考代碼1
n=int(input())
# n_base_2 代表2進制數,初始為空
n_base_16 = ''
# 直到n為0結束
while n:
# n%16獲得當前位,為int,需要轉換為str字符串
# 先求出低位,最后求得高位。所以是當前位+之前求的
if n%16>=10:
# 求出其距離'A'的值,使用chr函數轉換過去
n_base_16 = chr(ord('A')+n%16-10) + n_base_16
else:
# 不變
n_base_16 = str(n%16) + n_base_16
# 拋棄當前位
n = n // 16
print(n_base_16)
上面的代碼卻錯了,為什么呢,因為數據包含了0,但是我們程序不能對0進行處理,所以需要將其特判掉。
if n==0:
n_base_16 = '0'
當然我們也可以提前建好索引表。
參考代碼
n=int(input())
base_16_table = "0123456789ABCDEF"
# n_base_2 代表2進制數,初始為空
n_base_16 = ''
if n==0:
n_base_16 = '0'
# 直到n為0結束
while n:
# n%16獲得當前位,為int,直接利用索引表找到對應字母
# 先求出低位,最后求得高位。所以是當前位+之前求的
n_base_16 = base_16_table[n%16] + n_base_16
# 拋棄當前位
n = n // 16
print(n_base_16)
7284: 十六進制轉十進制 與二進制轉十進制同理。
可以嘗試下以下題目
7207: 二進制轉十六進制 我們可以將二進制數先轉換為十進制,再將其轉換為十六進制。也可以從后往前,四位一組將其轉換為十六進制的一位,余下的單獨算。
7285: 十六進制轉二進制我們可以把十六進制的每一位單獨轉換,但是第一位要去除前導0,其他不能去,模擬起來要判斷一下,可以嘗試一下。也可以把十進制當作中間進制進行轉換。
*八、任意進制轉換
可以先嘗試下以下題目
7030: 十進制轉八進制 、7019: 二進制轉八進制簡易版、1386: 十轉換轉R進制
1386: 十轉換轉R進制 涉及讀到文件末尾結束和一行多個數字,可以參照以下讀入方式。
1386讀入參考代碼
# 捕捉異常,讀取不到就結束
try:
while True:
# split對字符串分割,然后轉為int對應給n和r
n, r = map(int, input().split())
### 你的代碼
except:
pass
6198: Alice與進制轉換進階版
給定R1進制的n讓我們轉換為r2進制的,我們需要以十進制作為中間進制,先轉為十進制,最后再轉回r2進制。
參考代碼
base_16_table = "0123456789ABCDEF"
def convert_to_base_10(n_base_r1,r1):
num = 0
if n_base_r1[0] == '-':
# 是負數,把負號去除,結果乘上-1即可
sign = -1
n_base_r1 = n_base_r1[1:]
else:
sign = 1
for i in n_base_r1:
# find函數可以找到出現i的下標
num = num * r1 + base_16_table.find(i)
return sign * num
def convert_to_base_r2(n,r2):
if n<0:
# 記下符號,將其當正數處理
sign = -1
n = -n
else:
sign = 1
n_base_r2 = ''
# 0特別處理
if n == 0:
n_base_r2 = '0'
while n:
n_base_r2 = base_16_table[n%r2] + n_base_r2
n = n // r2
if sign == -1:
return '-'+n_base_r2
return n_base_r2
# 捕捉異常,讀取不到就結束
try:
while True:
# split對字符串分割,然后轉為int對應給n和r
n_base_r1, r1, r2 = map(str, input().split())
# 把r1進制的n轉換為十進制的
n = convert_to_base_10(n_base_r1,int(r1))
# 把十進制的n轉換為r2進制的
n_base_r2 = convert_to_base_r2(n,int(r2))
print(n_base_r2)
except:
pass