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

۴۷۲ بازدید
آخرین به‌روزرسانی: ۴ مهر ۱۴۰۲
زمان مطالعه: ۱۵ دقیقه

در این مقاله یک ماشین حساب سیستم عددی در پایتون می‌سازیم که با استفاده از آن می‌توانیم هر عددی را از هر مبنایی به مبنای دیگر تبدیل کنیم. «مبنا» (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 نیز به آن اضافه کنید. پیشنهاد می‌کنیم در زمان کدنویسی با یک مبدل آنلاین سیستم‌های عددی نیز کار کنید تا نتایج برنامه را با آن تطبیق بدهید. کد به صورت زیر است:

def menu():
    '''
    function holding the menu
    Returns: string
    '''
    return (
    '''
----------------------------------------------------------
Welcome to the Number Base converter!
The system will ask you for:
- The Number to convert
- What base you want to convert FROM
- What base you want to convert TO
** REMEMBER: All numbers must be integers!(unless HEX) **
----------------------------------------------------------
    ''')

def validate_bin(check_number):
    '''
    function that checks if the input consists of either 0 or 1.
    Binary numbers can only be 0 or 1, so we need to validate this
    before doing any math on it.
    returns: True/False
    '''
    check_list = [int(item) for item in (sorted(set(list(str(check_number)))))]

    for number in check_list:
        print (f'checking {number} - {type(number)}')
        if number not in [0,1]:
            print (f'invalid binary number')
            return False
    return True

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

def validator(input_number,input_base,output_base):
    if validate_input(input_number) and input_base.isdigit() and output_base.isdigit():

        if int(input_base) == 2:
            if not validate_bin(input_number):
                print ('ERROR: Invalid Binary Number. Must contain 0s or 1s')
                return False

        if input_number.isdigit() and input_number.isalpha():
            if int(input_base) != 16:
                print ('ERROR: Hexadesimal numbers requires base FROM to be 16')
                return False

        if int(input_base) == 1 or int(output_base) == 1:
            print (f'can not convert to or from Base-1')
            return False
        return True




def convert_number_system(input_number, input_base, output_base):
    '''
    function that calculates numbers from one base to the other
    returns: int, converted number
    '''

    #list that holds the numbers to output in the end
    remainder_list = []

    #start value for sum_base_10. All calculations go thorugh base-10.
    sum_base_10 = 0

    #validate_input


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

    # we coulc use python's built in hex(), but it is more fun not to...
    #if output_base == 16:
        #hex_repr = hex(input_number)
        #return hex_repr[2:]

    # we want to convert to base-10 before the actual calculation:
    elif input_base != 10:

        # reverse the string to start calculating from the least significant number
        reversed_input_number = input_number[::-1]

        #check if user typed in letter outside HEX range.
        hex_helper_dict = {'a' : 10 , 'b' : 11 , 'c' : 12 , 'd' : 13 , 'e' : 14 , 'f' : 15}


        for index, number in enumerate(reversed_input_number):
            for key,value in hex_helper_dict.items():
                if str(number).lower() == key:
                    number = value

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

    # if the number is already in Base-10, we can start the convertion
    elif input_base == 10:
        sum_base_10 = int(input_number)


    # we loop through until we hit 0. When we hit 0, we have our number.
    while sum_base_10 > 0:

        #find number to pass further down the loop
        divided = sum_base_10// int(output_base)

        #find remainder to keep
        remainder_list.append(str(sum_base_10 % int(output_base)))

        # the new value to send to the next iteration
        sum_base_10 = divided


    #fix the list and send a number:
    return_number = ''

    # if the user asked for a Hexadesimal output, we need to convert
    # any number from 10 and up.
    if output_base == 16:
        hex_dict = {10 : 'a' , 11 : 'b' , 12 : 'c' , 13 : 'd' , 14 : 'e' , 15 : 'f'}

        #loop through remainder_list and convert 10+ to letters.
        for index, each in enumerate(remainder_list):
            for key, value in hex_dict.items():
                if each == str(key):
                    remainder_list[index] = value

    #return the number:
    else:
        for each in remainder_list[::-1]:
            return_number += each

        return (return_number)
    #else:
        #return ('invalid input... Please Try Again')

def execute_converter():
    '''
    procedure that interacts with the user and sends it to get converted.
    '''
    user_number = ''
    user_input_base = ''
    user_output_base = ''

    proceed = 'y'

    while proceed.lower() == 'y':
        valid_input = False
        while valid_input == False:
            user_number = input('\nPlease type the number you wish to convert: ')
            user_input_base = input('Please type the base you wish to convert FROM (e.g. 10): ')
            user_output_base = input('Please type the base you wish to convert TO (e.g. 2): ')

            valid_input = validator(user_number,user_input_base,user_output_base)

        print (f'\nTrying to convert The Number {user_number} from a Base-{user_input_base} to a Base-{user_output_base}: ')
        print (f'>> RESULT: {convert_number_system(user_number, user_input_base, user_output_base)} <<')

        print (f'\nDo you wish to convert another number? Type y/n: ')
        proceed = input('')


    print (f'quitting converter...')

if __name__ == '__main__':
    #print the menu:
    print(menu())
    #execute the actual converter:
    execute_converter()

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

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

()def menu

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

return (
    '''
----------------------------------------------------------
Welcome to the Number Base converter!
The system will ask you for:
- The Number to convert
- What base you want to convert FROM
- What base you want to convert TO
** REMEMBER: All numbers must be integers!(unless HEX) **
----------------------------------------------------------
    ''')

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

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

(def validate_bin(check_number

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

def validate_bin(check_number):
    '''
    function that checks if the input consists of either 0 or 1.
    Binary numbers can only be 0 or 1, so we need to validate this
    before doing any math on it.
    returns: True/False
    '''
    check_list = [int(item) for item in set(list(check_number))]

    for number in check_list:
        if number not in [0,1]:
            print (f'invalid binary number')
            return False
    return True

ما نمی‌خواهیم یک رشته طولانی را که شامل چندین بار تکرار یک عدد است، بررسی کنیم. اگر آن را به یک set تبدیل کنیم، موارد تکراری پاک می‌‌شوند. Set-ها نمی‌توانند چند وهله تکراری از یک آیتم را نگه‌داری کنند. ما از «خلاصه‌سازی لیست» (list comprehension) برای تبدیل ورودی به یک int و بررسی آن با [0,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 بازگشت می‌دهد.

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

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

(def validator(input_number,input_base,output_base

def validator(input_number,input_base,output_base):
    if validate_input(input_number) and input_base.isdigit() and output_base.isdigit():

        if int(input_base) == 2:
            if not input_number.isdigit():
                print ('>>> ERROR: Input is not a digit. Binary Numbers contain 0s and 1s only. <<<')
                return False

            if not validate_bin(input_number):
                print ('>>> ERROR: Invalid Binary Number. Must contain 0s or 1s <<<')
                return False

        if input_number.isdigit() and input_number.isalpha():
        #if input_number.isalphanum():
            print ('found number and letter')
            if int(input_base) != 16:
                print ('>>> ERROR: Hexadesimal numbers requires base FROM to be 16 <<<')
                return False

        if int(input_base) == 1 or int(output_base) == 1:
            print (f'can not convert to or from Base-1')
            return False
        return True
    else:
        print(f'invalid input...Try again')
        return False

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

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

تبدیل

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

(...,def convert_number_system(input_number

def convert_number_system(input_number, input_base, output_base):
    '''
    function that calculates numbers from one base to the other
    returns: converted number
    '''

    #list that holds the numbers to output in the end
    remainder_list = []

    #start value for sum_base_10. All calculations go thorugh base-10.
    sum_base_10 = 0

    #validate_input


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

    # we coulc use python's built in hex(), but it is more fun not to...
    #if output_base == 16:
        #return hex(input_number)[2:]

    # we want to convert to base-10 before the actual calculation:
    elif input_base != 10:

        # reverse the string to start calculating from the least significant number
        reversed_input_number = input_number[::-1]

        #check if user typed in letter outside HEX range.
        hex_helper_dict = {'a' : 10 , 'b' : 11 , 'c' : 12 , 'd' : 13 , 'e' : 14 , 'f' : 15}
        for index, number in enumerate(reversed_input_number):
            for key,value in hex_helper_dict.items():
                if str(number).lower() == key:
                    number = value

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

    # if the number is already in Base-10, we can start the convertion
    elif input_base == 10:
        sum_base_10 = int(input_number)


    # we loop through until we hit 0. When we hit 0, we have our number.
    while sum_base_10 > 0:

        #find number to pass further down the loop
        divided = sum_base_10// int(output_base)

        #find remainder to keep
        remainder_list.append(str(sum_base_10 % int(output_base)))

        # the new value to send to the next iteration
        sum_base_10 = divided

    # if the user asked for a Hexadesimal output, we need to convert
    # any number from 10 and up.
    if int(output_base) == 16:
        hex_dict = {'10' : 'a' , '11' : 'b' , '12' : 'c' , '13' : 'd' , '14' : 'e' , '15' : 'f'}

        #loop through remainder_list and convert 10+ to letters.
        for index, each in enumerate(remainder_list):
            for key, value in hex_dict.items():
                if each == key:
                    remainder_list[index] = value

    return ''.join(remainder_list[::-1])
  • remainder_list تعدادی که می‌خواهیم بازگشت دهیم را شامل می‌شود. اگر بخش مباحث ریاضیاتی ابتدای مقاله را به خاطر داشته باشید، بی‌درنگ می‌توانید کلیدواژه remainder یعنی باقیمانده را تشخیص دهید.
  • sum_base_10 ما می‌خواهیم از مبنای 10 به عنوان یک گام میانی استفاده کنیم. مقدار اولیه را روی 0 تنظیم می‌کنیم و سپس همه مقادیر را بر مبنای آن محاسبه می‌کنیم.

خروجی دودویی

if output_base == 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

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

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

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

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

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

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

(int(number)*(int(input_base)**index))
6*(8**0)

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

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

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

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

عملیات ریاضی

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

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

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

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

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

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

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

# if the user asked for a Hexadesimal output, we need to convert
# any number from 10 and up.
if int(output_base) == 16:
    hex_dict = {'10' : 'a' , '11' : 'b' , '12' : 'c' , '13' : 'd' , '14' : 'e' , '15' : 'f'}

    #loop through remainder_list and convert 10+ to letters.
    for index, each in enumerate(remainder_list):
        for key, value in hex_dict.items():
            if each == key:
                remainder_list[index] = value

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

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

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

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

()def execute_converter

def execute_converter():
    '''
    procedure that interacts with the user and sends it to get converted.
    '''

    #proceed set to y/yes to initiate the while loop.
    proceed = 'y'

    while proceed.lower() == 'y':
        valid_input = False
        while valid_input == False:
            user_number = input('\nPlease type the number you wish to convert: ')
            user_input_base = input('Please type the base you wish to convert FROM (e.g. 10): ')
            user_output_base = input('Please type the base you wish to convert TO (e.g. 2): ')

            valid_input = validator(user_number,user_input_base,user_output_base)

        print (f'\nTrying to convert The Number {user_number} from a Base-{user_input_base} to a Base-{user_output_base}: ')
        print (f'>> RESULT: {convert_number_system(user_number, user_input_base, user_output_base)} <<')

        print (f'\nDo you wish to convert another number? Type \'y\' to continue:\nor any other character to quit.')
        proceed = input('')


    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

نظر شما چیست؟

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