進制轉換詳解,二進制,十進制,八進制,十六進制,62進制,MD5加密,python代碼示例


進制轉換詳解,二進制,十進制,八進制,十六進制,62進制,MD5加密,python代碼示例

進制關系講解:

1. 進制的產生:

首先說一下十進制,這是我們最熟悉的進制體系,理論上也是我們人類最先接觸的進制體系。
原因很簡單,我們人都有十個手指頭和十個腳指頭。這天然的對稱性,有着天然的數學規律在里面。
十進制是應用最廣泛,也最常用的進制體系,但是進制體系並不只屬於十進制。
第二個被發現,並廣泛使用的是二進制,大概有和無,也是最先被明白的道理吧。
從二進制開始人類才算真正打開進制世界的大門,並且一發不可收拾。
比如:太極陰陽,八卦,摩爾斯密碼,八進制,十六進制等等。

2. 進制原理:

進制實際上是一種數的認知和規律總結。
進制轉換實際上就是一種數與數之間的對應關系。(這一點和加密原理一樣)
既然是一種對應關系,那么一定存在某種我們人類認知的數學規則在里面。
最基礎的知識就是符號,進位和減位。
比如:15-7=8
實質上就是5-7=-2+10=8:這個過程可以理解為5減7,不夠向10借2,5+2=7,7-7=0
最后 10-2=8,這樣 10 借出 2 之后還剩 8,15-7=8.
在減法的基礎上,發展出除法,余數和商。除法,余數,商,這三個就是進位換算的數學基礎。

3. 十進制舉例:

首先人為定義一個數字范圍(符號)為:0,1,2,3,4,5,6,7,8,9
再定義一個進位規則:逢十進一
再定義一個顯示的規則:向左進位
    舉例說明:9+1=10
    9 已經是數字范圍的最大值,再加 1,只能向上進位,個位數變成 0,十位數變成 1
	組合起來按照向左進位顯示就是 10
    實際我們可以理解為每一個數的左邊都有無數的 0 位存在
如:0010,按照十進制理解是十, 10 前面的 0 被我們省略掉了而已。每一位可以顯示 0~9 的值
當位值達到9還要繼續增加的時候,實際上就是向上進位,自身歸 0,加法就是重復這個過程的規則
最后得到一個固定的組合值,顯示成一個數字,減法反之。
    能理解上面這段話,就基本上理解了進制規則和方法。
    舉例:100,按照十進制,解讀為:百位值:1,十位值:0,個位值:0
    100+100=200 的過程:百位值 1+1,十位 +0,個位 +0,最后顯示為:200

python代碼示例:

十進制轉二進制:

# 二進制:
# 1. 數字范圍:0,1
# 2. 進位規則:逢二進一
# 3. 顯示規則:向左進位

NUM = ["0", "1"]	# 數字范圍:0,1

def z2(func_num):	# 定義一個函數
    len_count = len(NUM)	# 得到進位規則的值
    result_value = []	# 定義一個空的列表用來放得到的新數據
    while func_num >= len_count:	# 循環比較當前的商是不是大於等於進位規則的值
        func_num,remain = divmod(func_num,len_count)	# 得到給定十進制數的商和余數
        result_value.append(NUM[remain])		# 把余數對應的數字范圍值按順序放進列表
    result_value.append(NUM[func_num])		# 把最后剩余的商對應的數字范圍值放進列表
    result_value.reverse()		# 反轉列表

    result = "".join(result_value)		# 把列表里的字符串拼接起來
    return result

test = z2(10)
print(test)

十進制轉八進制:

# 八進制:
# 1. 數字范圍:0~7
# 2. 進位規則:逢八進一
# 3. 顯示規則:向左進位

NUM = ["0", "1", "2", "3", "4", "5", "6", "7"]

def z8(func_num):
    len_count = len(NUM)
    result_value = []
    while func_num >= len_count:
        func_num, remain = divmod(func_num, len_count)
        result_value.append(NUM[remain])
    result_value.append(NUM[func_num])
    result_value.reverse()

    result = "".join(result_value)
    return result

test = z8(10)
print(test)

十進制轉十六進制:

# 十六進制:
# 1. 數字范圍:0~F
# 2. 進位規則:逢十六進一
# 3. 顯示規則:向左進位

NUM = ["0", "1", "2", "3", "4", "5", "6", "7","8","9","A","B","C","D","E","F"]

def z16(func_num):
    len_count = len(NUM)
    result_value = []
    while func_num >= len_count:
        func_num, remain = divmod(func_num, len_count)
        result_value.append(NUM[remain])
    result_value.append(NUM[func_num])
    result_value.reverse()

    result = "".join(result_value)
    return result

test = z16(10)
print(test)

十進制轉62進制:

# 62進制:
# 1. 數字范圍:0~9A~Za~z
# 2. 進位規則:逢62進一
# 3. 顯示規則:向左進位

import string
import itertools
# 實在是不想寫這個長列表了,string和itertools 模塊,其實也就是把這些字符變成字符串,放進列表
NUM = list(itertools.chain(string.digits, string.ascii_uppercase, string.ascii_lowercase))

def z62(func_num):
    len_count = len(NUM)
    result_value = []
    while func_num >= len_count:
        func_num, remain = divmod(func_num, len_count)
        result_value.append(NUM[remain])
    result_value.append(NUM[func_num])
    result_value.reverse()

    result = "".join(result_value)
    return result

test = z62(10)
print(test)

結語:

​ 可以看出,這些進制的本質都只是更換了數字范圍和進位規則
​ 於是通過十進制作為中間值,他們之間可以實現互相轉換。
​ 因為我們規定的向左進位的規則,導致左邊的位值大於右邊的位值
​ 所以實際的排列順序和除法所得余數的順序剛好相反:
​ 商>倒數第一個余數>倒數第二個余數>......>第一個余數。

為什么最后排序要反轉順序呢?
因為這就涉及到加權的概念,什么是加權呢?
舉例:十進制 90 > 9
其實 9 和 9 值是一樣的,為什么 90 就大於 9 呢?
因為 90 = 9 * 10  這個 10 就是權重
表明 9 現在代表的是十位上的 9 也就是 10 個 9 的意思
所以 10 個 9 自然大於 1 個 9

以整數 125 為例,轉換為二進制數:
我們規定的進位規則是:向左進位,這就導致了 左邊值>右邊值 [ 10 > 01 ]
下面我們看看二進制加權如何表示:

image

	125 的二進制表示就是:1111101
以上示例可以說明,二進制是如何加權的:左邊的權值 = 右邊權值 * 進位規則
先比較大小,再得到和位值的差,可以得到加權值和位值
但是減法效率太差,而且涉及到比對判斷

一般都是使用 除 2 取余法:
有商或者余數就代表該位權值位存在,余數值就是該位的具體值
權重來自於商的層數,而商的層數實際上是底層權值最高
為什么權重來自於商呢?
因為 125 按照進位規則除下去,最后一層就代表了 125 中最多包含 2 的 6 次方
( 2**6 < 125 < 2**7 )
然后每一層都比這一層少 2 倍
所以自上而下從右到左排列余數就是 125 的二進制數表示:1111101

image

因為我們人類習慣從左到右書寫,所以你可以理解為:
從左到右書寫就是余數的逆序(自下而上)
取余法圖示如下:

image

雖然很想把原碼,反碼,補碼都講透,把小數,負數也都加進去詳解,但是實在是時間和精力有限
在此只能解釋一下原理,不再寫代碼了:
1. 原碼:
一個二進制位字節(Byte)是 8 位(bit)不可分割的二進制數:00000001 代表十進制數 1
我們規定最左邊的一位 0 代表正數  1 代表負數:(這是人為規定,也是為了讓計算機能區分正負)
00000001 代表十進制數 1 ; 10000001  代表 -1 
但是按照上面的規定: 00000000 代表 0 ; 10000000 代表 -0  
按照值 0 = -0 ? 這樣對於計算機就會產生歧義,因為一個值有兩個表示,而且不利於計算
所以規定:00000000 代表 0  ; 10000000 代表 -128 
這樣就意味着一個Byte的值范圍: 01111111~10000000 (127~-128)
以上就是原碼:
四則運算對我們人來說很簡單,因為我們人能輕易的識別各種運算符(+ - * /)等等。
但是計算機不能識別運算符,所以計算機內部只能進行加減的運算。
乘法和除法是可以分解為加法和減法的,但是用原碼運算是必須要帶符號的:
1-1 = 00000001 + 10000001 = 00000001 - 00000001 = 0
可以看到要先把負數轉換為正數,然后相減,這讓我們人看的很清晰,但是對計算機是一種浪費

2. 小數:
十進制小數轉換為二進制數一般采用 乘 2 取整法:
小數 0.125 舉例如下圖:	  

image

3. 反碼和補碼:
於是根據數學原理,科學家引入了反碼和補碼,輔助計算機運算
規定正數的原碼,反碼和補碼就是本身。(因為反碼和補碼是為了負數設計的,方便減法運算)
負數的反碼為:符號位不變,按位取反,-1 10000001 反碼為 11111110
負數的補碼為:反碼 +1  -1 的反碼為 11111111
1-1 = 00000001 + 11111111 = 100000000(現在得到一個9位的數)  
超出 8 位,直接舍棄超出的值,這樣就得到 00000000 = 0
引入反碼和補碼,就把所有的數學運算全部統一成了加法,這樣計算機結構得以簡化,效率大大提高

補碼的原理:用 -1 舉例:

-1 的 原碼為: 10000001 這里的最高位 1 代表了負號(-)
-1 的 補碼為: 11111111 這里的最高位 1 代表了 -128	

image

如上圖,可以看到引入補碼,計算機的二進制運算脫離了正負符號和運算符,只需要加法就可以了

最后貢獻一段MD5的加密代碼:

加密本質上是定義了一個更深奧的數字范圍和進位規則,或者顯示規則。

加密和進制其實都只有一個作用就是讓人看不懂(開玩笑的)。

僅供參考:

MD5本質上是把我們認識的字符,通過哈希算法給隱藏起來,最后返回一個固定長度的字符串
這樣解決了兩個問題:
	1. 數字范圍太短,容易被遍歷算法破解,因為哈希算法加密的是字符串,理論上字符串無盡
	2. 密文太長,導致傳輸,攜帶,記憶等等的不方便
# 老規矩導模塊,我寫的手都快斷了!
# 這個沒加鹽
import hashlib

def encrypt(origin):
    origin_bytes = origin.encode('utf-8')
    md5_object = hashlib.md5()
    md5_object.update(origin_bytes)
    return md5_object.hexdigest()

p1 = encrypt('admin')
print(p1) # "21232f297a57a5a743894a0e4a801fc3"

加鹽版:

import hashlib

def encrypt(origin):
    salt = "鹽"
    origin_bytes = origin.encode('utf-8')
    md5_object = hashlib.md5(salt.encode("utf-8"))   # 這個地方加鹽
    md5_object.update(origin_bytes)
    return md5_object.hexdigest()

p1 = encrypt('admin')
print(p1) # "0956c330a0384f7daa08517619a940c5"


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM