کدنویسی ماشین حساب سیستم عددی در پایتون — از صفر تا صد

۱۲۰۸ بازدید
آخرین به‌روزرسانی: ۰۴ مهر ۱۴۰۲
زمان مطالعه: ۱۵ دقیقه
کدنویسی ماشین حساب سیستم عددی در پایتون — از صفر تا صد

در این مقاله یک ماشین حساب سیستم عددی در پایتون می‌سازیم که با استفاده از آن می‌توانیم هر عددی را از هر مبنایی به مبنای دیگر تبدیل کنیم. «مبنا» (Base) در سیستم‌های عددی به ما می‌گوید که چه تعداد رقم در اختیار داریم. سیستم «دودویی» (Binary) از دو رقم تشکیل یافته است. سیستم «هشت‌هشتی» (Octal) از هشت رقم تشکیل یافته و سیستم «ده‌دهی» یا «اعشاری» (Decimal) نیز دارای 10 رقم است.

برنامه‌ای که می‌خواهیم بنویسیم می‌تواند هر عدد را در هر مبنایی که به آن می‌دهیم مدیریت کند. تنظیم چنین سیستمی با درک ریاضیات پس‌زمینه آن کار ساده‌ای است. چیزی که می‌خواهیم طراحی کنیم. در نهایت مانند تصویر زیر خواهد بود:

ماشین حساب سیستم عددی در پایتون

آشنایی با ریاضیات سیستم‌های عددی

ماشین حسابی که در این مقاله می‌خواهیم طراحی کنیم، همانند هر ماشین حساب دیگری بر مبنای ریاضیات کار می‌کند. بنابراین باید دانش نظری خودمان در مورد تبدیل مبناهای عددی را یادآوری کنیم.

اگر در مدرسه با ریاضیات سرو کار داشته یا هر نوع تحصیلات آکادمیک در رشته کامپیوتر داشته‌اید، حتماً تاکنون با عملیات تبدیل یک عدد از یک مبنا به مبنای دیگر آشنا شده‌اید و احتمالاً جدول‌های دودویی یا صحبت از سیستم «ده‌دهی»، «هشت‌هشتی» و «شانزده‌شانزدهی» را به خاطر می‌آورید.

سیستم اعشاری (مبنای 10) سیستمی است که به طور روزمره برای شمارش همه چیز از آن استفاده می‌کنیم. ارقام این سیستم شامل 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 هستند. زمانی که این ارقام پایان یابند، موقعیت دیگری در سمت چپ عدد اضافه می‌کنیم و اعداد را به صورت 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 و غیره ادامه می‌دهیم. زمانی که دوباره این اعداد پایان یابند، یک موقعیت جدید دیگر اضافه می‌کنیم و اعداد را به صورت 100, 101, 102…118, 119, 120 اضافه می‌کنیم.

در مورد فرایند ساخت این اعداد تأمل زیادی نمی‌کنیم، چون از بدو کودکی با آن‌ها آشنا شده‌ایم، اما اگر از یک کودک بخواهید اعداد را در سیستم «هشت‌هشتی» بشمارد، بعید است موفقیت چندانی داشته باشد. اما تئوری همه سیستم‌های عددی آسان بوده و دقیقاً مشابه سیستم ده‌دهی است که به استفاده از آن چنین خو کرده‌ایم.

شمارش در سیستم هشت‌هشتی به صورت زیر است:

0,1,2,3,4,5,6,7 → 10,11,12,13,14,15,16,17 → 20,21…

تبدیل از یک مبنا به مبنایی دیگر

در ابتدا تبدیل اعداد از مبناهای دیگر به مبنای 10 را بررسی می‌کنیم. تبدیل از سیستم ده‌دهی به سیستم‌های دیگر کار بسیار آسانی است. از این رو بهتر است به بررسی تبدیل اعداد به سیستم ده‌دهی بپردازیم.

اگر دو سیستم ده‌دهی و هشت‌هشتی را در نظر بگیریم، برای آشنایی با روش تبدیل یک عدد از سیستم هشت‌هشتی به سیستم ‌ده‌‌دهی یک مثال را به صورت زیر بررسی می‌کنیم:

256(Base-8) →???(Base-10)

ما در عدد هشت‌هشتی خود سه موقعیت داریم که رقم 2 در موقعیت صدگان، 5 در موقعیت دهگان و 6 در موقعیت یکان است. این موقعیت‌ها می‌توانند ارقامی بین 0 تا 7 را داشته باشند. ما باید هر یک از این ارقام را به در همه موقعیت‌ها به سیستم ده‌دهی تبدیل کنیم. سیستم ده‌دهی دارای ده رقم از 0 تا 9 است.

روش انجام این تبدیل آن است که هر یک از اعداد را برداشته و آن را در مبنا به توان اندیس موقعیت ضرب می‌کنیم. اگر از کمترین رقم سمت راست آغاز کنیم، رقم 6 را در $${8^0}$$، رقم 5 را در $${8^1}$$ و رقم 2 را در $${8^2}$$ ضرب می‌کنیم. برای درک بهتر موضوع مراحل کار در تصویر زیر به نمایش درآمده است:

ماشین حساب سیستم عددی در پایتون

زمانی که عددی را در سیستم ده‌دهی داریم، تبدیل آن به مبناهای دیگر کار بسیار آسانی محسوب می‌شود. برای مثال فرض کنید می‌خواهیم عدد 174 را از مبنای 10 به مبنای 8 تبدیل کنیم که نتیجه 256 را ایجاد می‌کند.

برای یافتن اعداد در مبناهای دیگر، عدد را به طور مکرر بر آن مبنا تقسیم می‌کنیم و در هر مرحله باقیمانده‌ها را نگه می‌داریم. این باقی‌مانده‌ها عدد را در مبنای دیگر برای ما تشکیل می‌دهند. زمانی که باقی‌مانده‌ها به دست آمدند، عدد را از کم‌ارزش‌ترین رقم به پرارزش‌ترین رقم یعنی از انتها به بالا می‌خوانیم. بدین ترتب عدد جدید در مبنای جدید به دست می‌آید.

174/2 نتیجه 21.75 را به دست می‌دهد. چنان که می‌بینید 21 به رنگ قرمز و 0.75 به رنگ سبز است. ما 21 را به خط بعدی می‌فرستیم و با 0.75 کار می‌کنیم. اگر 0.75 را در مبنا ضرب کنیم باقیمانده به دست می‌آید. این عدد به سمت راست ارسال می‌شود و رنگ آن آبی است. زمانی که به 0 برسیم رسماً کار انجام یافته است و عدد را در مبنای جدید به دست آورده‌ایم.

ماشین حساب سیستم عددی در پایتون

به این ترتیب نه تنها می‌توانیم از مبنای 10 به مبنای 8 برویم، بلکه به طور معکوس نیز می‌توانیم عمل کنیم. ما می‌توانیم از مبنای X به مبنای Y برویم.

کدنویسی

اینک نوبت به کدنویسی رسیده است. در این مقاله اغلب بخش‌های کد را به صورت دستی می‌نویسیم و از کتابخانه‌ها استفاده نمی‌کنیم، زیرا می‌خواهیم بیشترین حد از یادگیری را داشته باشیم. در این کد از تابع‌های پایتون مانند ()bin استفاده نکرده‌ایم، زیرا می‌خواهیم همه چیز را به صورت دستی بنویسیم. در محیط پروداکشن معمولاً باید همه چیز در حد امکان کوتاه باشد و بنابراین به جای کدنویسی دستی همه بخش‌ها از کتابخانه‌ها برای حل مسائل استفاده می‌کنیم.

این برنامه صرفاً یک فایل به نام main.py است و همه کدها در یک سند قرار دارند. البته شما می‌توانید آن را بسته به میل خود بسط دهید. مثلاً یک کلاس Number داشته باشید و حتی GUI نیز به آن اضافه کنید. پیشنهاد می‌کنیم در زمان کدنویسی با یک مبدل آنلاین سیستم‌های عددی نیز کار کنید تا نتایج برنامه را با آن تطبیق بدهید. کد به صورت زیر است:

1def menu():
2    '''
3    function holding the menu
4    Returns: string
5    '''
6    return (
7    '''
8----------------------------------------------------------
9Welcome to the Number Base converter!
10The system will ask you for:
11- The Number to convert
12- What base you want to convert FROM
13- What base you want to convert TO
14** REMEMBER: All numbers must be integers!(unless HEX) **
15----------------------------------------------------------
16    ''')
17
18def validate_bin(check_number):
19    '''
20    function that checks if the input consists of either 0 or 1.
21    Binary numbers can only be 0 or 1, so we need to validate this
22    before doing any math on it.
23    returns: True/False
24    '''
25    check_list = [int(item) for item in (sorted(set(list(str(check_number)))))]
26
27    for number in check_list:
28        print (f'checking {number} - {type(number)}')
29        if number not in [0,1]:
30            print (f'invalid binary number')
31            return False
32    return True
33
34def validate_input(input_number):
35    '''
36    function that checks if the input consists of legal characters.
37    Binary numbers can only be 0 or 1, so we need to validate this
38    before doing any math on it.
39    returns: True/False
40    '''
41    legal_char = '0123456789abcdef'
42    for number in input_number:
43        if number not in legal_char:
44            return False
45    return True
46
47def validator(input_number,input_base,output_base):
48    if validate_input(input_number) and input_base.isdigit() and output_base.isdigit():
49
50        if int(input_base) == 2:
51            if not validate_bin(input_number):
52                print ('ERROR: Invalid Binary Number. Must contain 0s or 1s')
53                return False
54
55        if input_number.isdigit() and input_number.isalpha():
56            if int(input_base) != 16:
57                print ('ERROR: Hexadesimal numbers requires base FROM to be 16')
58                return False
59
60        if int(input_base) == 1 or int(output_base) == 1:
61            print (f'can not convert to or from Base-1')
62            return False
63        return True
64
65
66
67
68def convert_number_system(input_number, input_base, output_base):
69    '''
70    function that calculates numbers from one base to the other
71    returns: int, converted number
72    '''
73
74    #list that holds the numbers to output in the end
75    remainder_list = []
76
77    #start value for sum_base_10. All calculations go thorugh base-10.
78    sum_base_10 = 0
79
80    #validate_input
81
82
83    if output_base == 2:
84        binary_repr = bin(input_number)
85        return (binary_repr[2:])
86
87    # we coulc use python's built in hex(), but it is more fun not to...
88    #if output_base == 16:
89        #hex_repr = hex(input_number)
90        #return hex_repr[2:]
91
92    # we want to convert to base-10 before the actual calculation:
93    elif input_base != 10:
94
95        # reverse the string to start calculating from the least significant number
96        reversed_input_number = input_number[::-1]
97
98        #check if user typed in letter outside HEX range.
99        hex_helper_dict = {'a' : 10 , 'b' : 11 , 'c' : 12 , 'd' : 13 , 'e' : 14 , 'f' : 15}
100
101
102        for index, number in enumerate(reversed_input_number):
103            for key,value in hex_helper_dict.items():
104                if str(number).lower() == key:
105                    number = value
106
107            sum_base_10 += (int(number)*(int(input_base)**index))
108
109    # if the number is already in Base-10, we can start the convertion
110    elif input_base == 10:
111        sum_base_10 = int(input_number)
112
113
114    # we loop through until we hit 0. When we hit 0, we have our number.
115    while sum_base_10 > 0:
116
117        #find number to pass further down the loop
118        divided = sum_base_10// int(output_base)
119
120        #find remainder to keep
121        remainder_list.append(str(sum_base_10 % int(output_base)))
122
123        # the new value to send to the next iteration
124        sum_base_10 = divided
125
126
127    #fix the list and send a number:
128    return_number = ''
129
130    # if the user asked for a Hexadesimal output, we need to convert
131    # any number from 10 and up.
132    if output_base == 16:
133        hex_dict = {10 : 'a' , 11 : 'b' , 12 : 'c' , 13 : 'd' , 14 : 'e' , 15 : 'f'}
134
135        #loop through remainder_list and convert 10+ to letters.
136        for index, each in enumerate(remainder_list):
137            for key, value in hex_dict.items():
138                if each == str(key):
139                    remainder_list[index] = value
140
141    #return the number:
142    else:
143        for each in remainder_list[::-1]:
144            return_number += each
145
146        return (return_number)
147    #else:
148        #return ('invalid input... Please Try Again')
149
150def execute_converter():
151    '''
152    procedure that interacts with the user and sends it to get converted.
153    '''
154    user_number = ''
155    user_input_base = ''
156    user_output_base = ''
157
158    proceed = 'y'
159
160    while proceed.lower() == 'y':
161        valid_input = False
162        while valid_input == False:
163            user_number = input('\nPlease type the number you wish to convert: ')
164            user_input_base = input('Please type the base you wish to convert FROM (e.g. 10): ')
165            user_output_base = input('Please type the base you wish to convert TO (e.g. 2): ')
166
167            valid_input = validator(user_number,user_input_base,user_output_base)
168
169        print (f'\nTrying to convert The Number {user_number} from a Base-{user_input_base} to a Base-{user_output_base}: ')
170        print (f'>> RESULT: {convert_number_system(user_number, user_input_base, user_output_base)} <<')
171
172        print (f'\nDo you wish to convert another number? Type y/n: ')
173        proceed = input('')
174
175
176    print (f'quitting converter...')
177
178if __name__ == '__main__':
179    #print the menu:
180    print(menu())
181    #execute the actual converter:
182    execute_converter()

منطق پشت این کد آن است که سه آرگومان را به شرح زیر به تابع ()convert_number_system ارسال می‌کنیم:

  • input_number عددی است که می‌خواهیم تبدیل شود.
  • input_base مبنایی است که از آن تبدیل می‌کنیم.
  • output_base مبنایی است که به آن تبدیل می‌کنیم.

()def menu

منویی به صورت زیر ایجاد می‌کنیم. این تابع کل رشته منو را بازگشت می‌دهد و از این رو می‌توانیم آن را هر جایی که می‌خواهیم تنظیم کنیم. لازم نیست در مورد newline نیز نگران باشیم.

1return (
2    '''
3----------------------------------------------------------
4Welcome to the Number Base converter!
5The system will ask you for:
6- The Number to convert
7- What base you want to convert FROM
8- What base you want to convert TO
9** REMEMBER: All numbers must be integers!(unless HEX) **
10----------------------------------------------------------
11    ''')

تابع‌های اعتبارسنجی

به جای این که ورودی را در تابع مبدل بررسی کنیم، یک سری تابع‌های اعتبارسنجی ایجاد می‌کنیم که این کار را برای ما انجام می‌دهند. بدین ترتیب کد ما قابلیت استفاده مجدد می‌یابد.

(def validate_bin(check_number

این تابع بررسی می‌کند آیا عدد یک عدد دودویی معتبر است یا نه.

1def validate_bin(check_number):
2    '''
3    function that checks if the input consists of either 0 or 1.
4    Binary numbers can only be 0 or 1, so we need to validate this
5    before doing any math on it.
6    returns: True/False
7    '''
8    check_list = [int(item) for item in set(list(check_number))]
9
10    for number in check_list:
11        if number not in [0,1]:
12            print (f'invalid binary number')
13            return False
14    return True

ما نمی‌خواهیم یک رشته طولانی را که شامل چندین بار تکرار یک عدد است، بررسی کنیم. اگر آن را به یک set تبدیل کنیم، موارد تکراری پاک می‌‌شوند. Set-ها نمی‌توانند چند وهله تکراری از یک آیتم را نگه‌داری کنند. ما از «خلاصه‌سازی لیست» (list comprehension) برای تبدیل ورودی به یک int و بررسی آن با [0,1] استفاده می‌کنیم:

1[int(item) for item in set(list(check_number))]

همچنین رشته‌ها را از ورودی کاربر می‌گیریم و مقادیر integer را از ورودی مورد نیاز می‌سازیم. (int(item موجب می‌شود مطمئن شویم که همه اعداد به صورت عدد صحیح (Integer) هستند. عملکرد ما در پس‌زمینه به صورت زیر است:

‘10010011’ → [‘1’,’0',’0',’1',’0',’0',’1',’1'] → [0,1]

اگر 0 در [0,1] باشد، بررسی نتیجه مطلوب را به دست می‌دهد، اگر 1 در بازه [0,1] باشد باز نتیجه مطلوب به دست می‌آید. اگر عددی مانند 23 داشته باشیم که هر دو رقم شکست بخورند، تابع مقدار false بازگشت می‌دهد.

1def validate_input(input_number):
2    '''
3    function that checks if the input consists of legal characters.
4    Binary numbers can only be 0 or 1, so we need to validate this
5    before doing any math on it.
6    returns: True/False
7    '''
8    legal_char = '0123456789abcdef'
9    for number in input_number:
10        if number not in legal_char:
11            return False
12    return True

کد فوق نکته خاصی ندارد و بررسی می‌کند آیا ورودی شامل کاراکترهای منطقی تعریف شده است یا نه. ما با ارقام 0-9 و به دلیل وجود سیستم HEX از حروف a-f نیز به عنوان ورودی‌های معتبر استفاده می‌کنیم.

(def validator(input_number,input_base,output_base

1def validator(input_number,input_base,output_base):
2    if validate_input(input_number) and input_base.isdigit() and output_base.isdigit():
3
4        if int(input_base) == 2:
5            if not input_number.isdigit():
6                print ('>>> ERROR: Input is not a digit. Binary Numbers contain 0s and 1s only. <<<')
7                return False
8
9            if not validate_bin(input_number):
10                print ('>>> ERROR: Invalid Binary Number. Must contain 0s or 1s <<<')
11                return False
12
13        if input_number.isdigit() and input_number.isalpha():
14        #if input_number.isalphanum():
15            print ('found number and letter')
16            if int(input_base) != 16:
17                print ('>>> ERROR: Hexadesimal numbers requires base FROM to be 16 <<<')
18                return False
19
20        if int(input_base) == 1 or int(output_base) == 1:
21            print (f'can not convert to or from Base-1')
22            return False
23        return True
24    else:
25        print(f'invalid input...Try again')
26        return False

این تابع از تابع‌های اعتبارسنجی دیگر استفاده کرده و همه ورودی‌ها را اعتبارسنجی می‌کند. بدین ترتیب اگر نکته‌ای در پیش از ادامه کار وجود داشته باشد متوجه می‌شویم.

  • ابتدا بررسی می‌شود آیا یک عدد یا یک مقدار HEX وارد شده است.
  • سپس مبناها بررسی می‌شود. اگر برای input_base مقدار 2 وارد شده باشد، یعنی عدد باینری را تبدیل می‌کنیم. از این رو input_number باید صرفاً شامل ارقام 0 و 1 باشد.
  • اگر ورودی شامل حرف و رقم باشد یک عدد شانزده‌شانزدهی است. بنابراین اگر input_base مقدار 16 نباشد، نمی‌توانیم آن را تبدیل کنیم. HEX یک عدد با مبنای 16 است و هر مبنای دیگری محاسبه نادرستی به دست می‌دهد. می‌توانیم یک ورودی از پیش کامل شده در طی تعامل با کاربر و زمانی که عدد شانزده‌شانزدهی وارد می‌کند نیز داشته باشیم.
  • در نهایت بررسی می‌کنیم آیا کاربر تلاش کرده از مبنای 1 یا به آن تبدیل کند یا نه. این کار امکان‌پذیر نیست و از این رو به جای کرش کردن برنامه یک خطا بازگشت می‌دهیم.

تبدیل

اکنون به بخش اصلی کد خود می‌رسیم. این همان جایی است که باید از مهارت‌های ریاضیاتی خود استفاده کنیم. این تابع عملیاتی که قبلاً بررسی کردیم را اجرا می‌کند و چند گام امنیتی نیز دارد تا مطمئن شویم که خروجی صحیحی ارائه می‌کنیم.

(...,def convert_number_system(input_number

1def convert_number_system(input_number, input_base, output_base):
2    '''
3    function that calculates numbers from one base to the other
4    returns: converted number
5    '''
6
7    #list that holds the numbers to output in the end
8    remainder_list = []
9
10    #start value for sum_base_10. All calculations go thorugh base-10.
11    sum_base_10 = 0
12
13    #validate_input
14
15
16    if output_base == 2:
17        return (bin(input_number)[2:])
18
19    # we coulc use python's built in hex(), but it is more fun not to...
20    #if output_base == 16:
21        #return hex(input_number)[2:]
22
23    # we want to convert to base-10 before the actual calculation:
24    elif input_base != 10:
25
26        # reverse the string to start calculating from the least significant number
27        reversed_input_number = input_number[::-1]
28
29        #check if user typed in letter outside HEX range.
30        hex_helper_dict = {'a' : 10 , 'b' : 11 , 'c' : 12 , 'd' : 13 , 'e' : 14 , 'f' : 15}
31        for index, number in enumerate(reversed_input_number):
32            for key,value in hex_helper_dict.items():
33                if str(number).lower() == key:
34                    number = value
35
36            sum_base_10 += (int(number)*(int(input_base)**index))
37
38    # if the number is already in Base-10, we can start the convertion
39    elif input_base == 10:
40        sum_base_10 = int(input_number)
41
42
43    # we loop through until we hit 0. When we hit 0, we have our number.
44    while sum_base_10 > 0:
45
46        #find number to pass further down the loop
47        divided = sum_base_10// int(output_base)
48
49        #find remainder to keep
50        remainder_list.append(str(sum_base_10 % int(output_base)))
51
52        # the new value to send to the next iteration
53        sum_base_10 = divided
54
55    # if the user asked for a Hexadesimal output, we need to convert
56    # any number from 10 and up.
57    if int(output_base) == 16:
58        hex_dict = {'10' : 'a' , '11' : 'b' , '12' : 'c' , '13' : 'd' , '14' : 'e' , '15' : 'f'}
59
60        #loop through remainder_list and convert 10+ to letters.
61        for index, each in enumerate(remainder_list):
62            for key, value in hex_dict.items():
63                if each == key:
64                    remainder_list[index] = value
65
66    return ''.join(remainder_list[::-1])
  • remainder_list تعدادی که می‌خواهیم بازگشت دهیم را شامل می‌شود. اگر بخش مباحث ریاضیاتی ابتدای مقاله را به خاطر داشته باشید، بی‌درنگ می‌توانید کلیدواژه remainder یعنی باقیمانده را تشخیص دهید.
  • sum_base_10 ما می‌خواهیم از مبنای 10 به عنوان یک گام میانی استفاده کنیم. مقدار اولیه را روی 0 تنظیم می‌کنیم و سپس همه مقادیر را بر مبنای آن محاسبه می‌کنیم.

خروجی دودویی

1if output_base == 2:
2    return (bin(input_number)[2:])

اگر کاربر بخواهد یک خروجی دودویی داشته باشد، می‌توانیم از تابع داخلی ()bin استفاده کنیم. لزومی به این کار وجود ندارد، زیرا مبانی ریاضیات آن یکسان است و مهم نیست چه مقداری ارسال می‌کنیم، اما بررسی آن ضرری ندارد.

()bin مقدار 0b بازگشت می‌دهد که دودویی است. مقدار 0b به ما اعلام می‌کند که یک عدد دودویی است. ما باید یک عدد واقعی بازگشت دهیم. به همین جهت از [2:] استفاده می‌کنیم. اگر کد را در ترمینال اجرا کنید، تفاوت را می‌بینید:

>>> check_number = 23
>>> print(bin(check_number))
0b10111
>>> print(bin(check_number)[2:])
101114

این کد از اندیس 2 به بعد را پرینت می‌کند.

توجه کنید که نسخه ‌()hex را در کد قرار داده‌ایم، اما کامنت شده است. شما می‌توانید در صورت نیاز از آن استفاده کنید.

زمانی که مبنا 10 نباشد

اگر مبنا 10 نباشد، از گام میانی خود استفاده می‌کنیم. ابتدا لیست را معکوس می‌کنیم. معکوس کردن لیست در پایتون از طریق کد داخلی [::-1] میسر است:

reversed_input_number = input_number[::-1]

hex_helper_dict به ما کمک می‌کند که اعداد بالاتر از 9 را در صورت ورود مقدار hex مدیریت کنیم. اگر فرمول را به خاطر داشته باشید، باید اعداد را در هر موقعیت با اندیس مبنا به توان موقعیت ضرب کنیم. برای تبدیل عدد 256 از مبنای هشت به ده به صورت زیر عمل می‌کنیم:

2*(8²) + 5*(8¹) + 6*(8⁰) = 174

اگر عدد مانند 23e در مبنای شانزده باشد، در عمل به صورت 2، 3 و 14 خوانده می‌شود:

2*(16²) + 3*(16¹) + 14*(16⁰) = 574

این حلقه همه این کارها را برای ما انجام می‌دهد:

1for index, number in enumerate(reversed_input_number):
2    for key,value in hex_helper_dict.items():
3        if str(number).lower() == key:
4            number = value
5    sum_base_10 += (int(number)*(int(input_base)**index))

در کد فوق می‌بینید که هم از enumerate و هم از ()items. استفاده کرده‌ایم تا مطمئن شویم که می‌توانیم به همه موارد لازم برای اجرای عملیات دسترسی داشته بباشیم.

با استفاده از enumerate می‌توانیم هم به مقدار و هم اندیس متغیر دسترسی پیدا کنیم. زمانی که روی متغیر حلقه تعریف می‌کنیم بررسی می‌کنیم آیا عدد معادل کلیدی در دیکشنری است یا نه. در مورد 23e چنین است و باید عدد را به جای آن روی 14 تنظیم کنیم تا بتوانیم از محاسبات واقعی بهره بگیریم.

sum_base_10 += (int(number)*(int(input_base)**index))

اکنون که مطمئن شدیم هیچ عددی در واقع حرف نیست، می‌توانیم روی ارقام بچرخیم و عملیات را اجرا کنیم. برای هر رقم یک بار حلقه را اجرا کرده و ضرب را به طوری که قبلاً مطرح شد اجرا می‌کنیم.

1(int(number)*(int(input_base)**index))
26*(8**0)

این مقادیر در نهایت به sum_base_10 اضافه می‌شوند

زمانی که مبنا 10 باشد

تا اینجا ما موفق شده‌ایم عدد ورودی را به مبنای 10 (sum_base_10) ببریم.

1elif input_base == 10:
2    sum_base_10 = int(input_number)

عملیات ریاضی

اکنون که مقدار را در مبنای 10 داریم، می‌توانیم تقسیم را اجرا کنم تا باقیمانده‌ها را یافته و عدد جدید را به دست آوریم.

1while sum_base_10 > 0:
2    divided = sum_base_10// int(output_base)
3    remainder_list.append(str(sum_base_10 % int(output_base))
4    sum_base_10 = divided

ما باید تا زمان رسیدن به باقیمانده 0 تقسیم را ادامه بدهیم. این حلقه حصول چنین نتیجه‌ای را تضمین می‌کند.

با استفاده از تقسیم floor یعنی عملگر // اعداد تقسیم می‌شوند و بخش صحیح خارج‌قسمت جدا می‌شود. این بدان معنی است که تنها عدد 21 انتقال می‌یابد و بخش اعشاری 0.75 در مثال اولیه مقاله محاسبه نمی‌شود. با انتساب این عدد به مقسوم می‌توانیم این مقدار را به sum_base_10 بفرستیم تا در چرخه بعدی تقسیم استفاده شود.

با استفاده از عملگر % باقیمانده را به دست می‌آوریم. این مقدار به remainder_list الحاق می‌شود و می‌توانیم آن را بعداً در خروجی ارائه کنیم. این یک حلقه while است که تا زمان رسیدن به مقدار صفر ادامه می‌یابد.

زمانی که مبنا 16 باشد

اگر مقدار output_base برابر با 16 باشد، به آن معنی است که خروجی باید شانزده‌شانزدهی باشد. بدین ترتیب باید همه ارقام بالاتر از 9 را به حرف تبدیل کنیم:

1# if the user asked for a Hexadesimal output, we need to convert
2# any number from 10 and up.
3if int(output_base) == 16:
4    hex_dict = {'10' : 'a' , '11' : 'b' , '12' : 'c' , '13' : 'd' , '14' : 'e' , '15' : 'f'}
5
6    #loop through remainder_list and convert 10+ to letters.
7    for index, each in enumerate(remainder_list):
8        for key, value in hex_dict.items():
9            if each == key:
10                remainder_list[index] = value

همانند قبل یک دیکشنری برای تسهیل تبدیل ایجاد می‌کنیم. اگر یک مورد تطبیق پیدا شد، رقم را به حرف تبدیل کرده و به لیست الحاق می‌کنیم.

در نهایت خروجی به صورت زیر ارائه می‌شود:

return ''.join(remainder_list[::-1])

کد فوق لیست را معکوس می‌سازد و به صورت رشته‌ای درمی‌آورد که امکان بازگشت آن وجود دارد. اگر بخواهید یک مقدار int بازگشت دهید، می‌توانید از ()int استفاده کنید. در هر حال در صورتی که کاربر عددی در مبنای شانزده می‌خواهید مطمئن شوید که ارقام Hexadecimal را لحاظ کرده‌اید.

()def execute_converter

1def execute_converter():
2    '''
3    procedure that interacts with the user and sends it to get converted.
4    '''
5
6    #proceed set to y/yes to initiate the while loop.
7    proceed = 'y'
8
9    while proceed.lower() == 'y':
10        valid_input = False
11        while valid_input == False:
12            user_number = input('\nPlease type the number you wish to convert: ')
13            user_input_base = input('Please type the base you wish to convert FROM (e.g. 10): ')
14            user_output_base = input('Please type the base you wish to convert TO (e.g. 2): ')
15
16            valid_input = validator(user_number,user_input_base,user_output_base)
17
18        print (f'\nTrying to convert The Number {user_number} from a Base-{user_input_base} to a Base-{user_output_base}: ')
19        print (f'>> RESULT: {convert_number_system(user_number, user_input_base, user_output_base)} <<')
20
21        print (f'\nDo you wish to convert another number? Type \'y\' to continue:\nor any other character to quit.')
22        proceed = input('')
23
24
25    print (f'quitting converter...')

اینک بخش غالب کد ما به پایان رسیده است. بخش آخر پازل تعامل با کاربر است. این بخش شامل یک حلقه while سرراست است که کاربر اعدادی را در آن وارد می‌کند و ما آن‌ها را اعتبارسنجی کرده و در صورت پاس شدن اعتبارسنجی مبدل را اجرا می‌کنیم. کاربر این گزینه را در اختیار دارد که هر چه قدر می‌خواهد اعداد را وارد کند.

معمولاً بهتر است تعامل‌های با کاربر را در حلقه‌های while با استفاده از یک متغیر مانند proceed که اینجا استفاده کرده‌ایم اجرا کنیم. بدین ترتیب کاربر می‌تواند هر چه قدر می‌خواهد عدد وارد کند. این تعامل دو سطح دارد. حلقه while اول حلقه main را با کد 'proceed.lower() == ‘y مقداردهی می‌کند.

حلقه دوم valid_input=False را اعلان می‌کند، زیرا می‌خواهیم همه ورودی‌ها را پیش از ارسال آن به ()convert_number_system اعتبارسنجی کنیم. تا زمانی که نتیجه مقدار False دارد باید ورودی جدیدی وارد شود. پس از آن که کاربر ورودی خود را ارائه کرد، تابع اعتبارسنجی اجرا می‌شود. اگر اعتبارسنجی پاس شود، می‌توانیم ()convert_number_system را مقداردهی کنیم.

در نهایت از کاربر می‌خواهیم که اگر تمایل دارد عدد دیگری را امتحان کند. اگر کاربر مقدار y وارد کند کد دوباره اجرا می‌شود. با وارد کردن هر مقدار دیگری برنامه پایان می‌یابد.

به عنوان یک روش جایگزین می‌توانیم از کاربر بخواهیم که عدد مورد نظر خود برای تبدیل را وارد کرده و یا از برنامه خارج شود. این کار در متغیر number_input انجام می‌شود.

سخن پایانی

برنامه ما چندین جنبه مهم دارد. نخست باید مسئله را پیدا کنیم. مسئله این است که تبدیل دستی اعداد به سیستم‌های عددی مختلف کاری زمان‌گیر است. سپس روش ریاضیاتی حل مسئله را می‌یابیم. چنان که مشخص شد با استفاده از فرمول مورد بحث می‌توانیم هر عددی را به عدد دیگر تبدیل کنیم. کافی است ورودی دودویی و شانزده‌شانزدهی را مدیریت کنیم و مطمئن شویم که مبنای 1 را محاسبه نمی‌کنیم. این بدان معنی است که از تابع‌ها برای مدیریت کد استفاده می‌کنیم. همه کد برنامه درون یک منو قرار گرفته است که با کاربر تعامل می‌یابد و کد اجرایی زیرین در پس‌زمینه اجرا می‌شود. امیدواریم از مطالعه این مقاله لذت برده باشید.

اگر این مطلب برای شما مفید بوده است، آموزش‌های زیر نیز به شما پیشنهاد می‌شوند:

==

بر اساس رای ۲ نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
towardsdatascience
نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *