دودویی، هشتهشتی و شانزدهشانزدهی (که به آن هگز هم میگویند) دستگاههای اعداد گوناگونی با مبنای متفاوتاند. مبنای دودویی ۲ است، مبنای هشتهشتی ۸ و مبنای شانزدهشانزدهی ۱۶. عددهای صحیح معمولی در Crystal مبنای ۱۰ دارند. دودویی، هشتهشتی و شانزدهشانزدهی همه نمایشهایی از عددهای صحیح هستند. یعنی عددهای مثبت و منفی (از جمله صفر) را بدون کسر یا اعشار نشان میدهند و همهی عملیاتی را که میتوانیم با عددهای صحیح انجام دهیم پشتیبانی میکنند.
دودویی یک دستگاه اعداد با مبنای ۲ است که فقط از رقمهای ۰ و ۱ استفاده میکند. این دستگاه معمولاً حالتهای ۰ («خاموش») و ۱ («روشن») جریان برق گذرنده از ترانزیستورها و کلیدهای رایانه را نشان میدهد و نیز بارهای مثبت و منفی را در رسانههای ذخیرهسازی مغناطیسی. دودویی میتواند همهی عددهای صحیحی را که در مبنای ۱۰ به کار میروند نمایش دهد.
بخشی از دستگاه مبنای ۲ چنین است، هرچند تا بینهایت ادامه دارد و به ۱۲۸ ختم نمیشود:
| ۱۲۸ | ۶۴ | ۳۲ | ۱۶ | ۸ | ۴ | ۲ | ۱ |
|---|---|---|---|---|---|---|---|
| ۲ ** ۷ | ۲ ** ۶ | ۲ ** ۵ | ۲ ** ۴ | ۲ ** ۳ | ۲ ** ۲ | ۲ ** ۱ | ۲ ** ۰ |
پس اگر بخواهیم عدد ۶ را نمایش دهیم، در دودویی چنین میشود: ۱۱۰
| ارزش مکانی | ۴ | ۲ | ۱ |
|---|---|---|---|
| عدد دودویی | ۱ | ۱ | ۰ |
و عملیات چنین میشود: 4 + 2 + 0 = 6
مثال دیگر: ۱۹
| ارزش مکانی | ۱۶ | ۸ | ۴ | ۲ | ۱ |
|---|---|---|---|---|---|
| عدد دودویی | ۱ | ۰ | ۰ | ۱ | ۱ |
عدد دودویی چنین میشود: ۱۰۰۱۱
و عملیات چنین میشود: 16 + 0 + 0 + 2 + 1 = 19
در Crystal میتوانیم لیترالهای دودویی را با پیشوند 0b بنویسیم.
اگر 0b10011 بنویسیم، Crystal آن را عددی دودویی تفسیر میکند و به مبنای ۱۰ تبدیل میکند.
0b10011
# => 19
typeof(0b10011)
# => Int32
اگر عددی با پیشوند 0b بنویسید که در دستگاه دودویی نیست، خطای کامپایل ایجاد میشود.
0b10211
# => Error: unexpected token: "211"
چون عددهای دودویی خودشان عدد صحیح هستند، میتوانیم همهی عملیاتی را که با عددهای صحیح انجام میدهیم روی آنها هم انجام دهیم.
0b10011 + 0b10011
# => 38
0b10011 * 0b10011
# => 361
0b10011 / 3
# => 6.333333333333333
Crystal یک لیترال دودویی را بهطور خودکار به Int32 تبدیل میکند.
برای تبدیل یک Int32 به نمایش دودویی، از متد <int>.to_s(base) با آرگومان base برابر ۲ استفاده کنید.
این متد یک نمایش رشتهای از عدد دودویی برمیگرداند:
19.to_s(2)
# => "10011"
برای تبدیل نمایش رشتهای یک عدد دودویی به عدد صحیح، میتوانیم از متد <int>.to_i(base) استفاده کنیم و مبنای (۲) را بهعنوان آرگومان بدهیم:
"10011".to_i(2)
# => 19
اگر مبنای نادرست (یا یک نمایش دودویی نامعتبر) بدهید، خطای ArgumentError ایجاد میشود:
"011021".to_i(2)
# => Invalid Int32: "011021" (ArgumentError)
متدهایی وجود دارند که میتوان آنها را روی عددهای صحیح به کار برد تا اطلاعاتی دربارهی نمایش دودویی عدد به دست آورد.
<int>.bit_length تعداد بیتهایی را برمیگرداند که برای نمایش عدد لازم است:
19.bit_length
# => 5
<int>.bit(index) بیت موجود در اندیس دادهشده را برمیگرداند، با شمارش از سمت راست (کمارزشترین بیت):
19.bit(0)
# => 1
0b10011.bit(1)
# => 1
هشتهشتی یک دستگاه اعداد با مبنای ۸ است. از رقمهای ۰، ۱، ۲، ۳، ۴، ۵، ۶ و ۷ استفاده میکند.
در Crystal میتوانیم عددهای هشتهشتی را با پیشوند 0o نمایش دهیم.
مانند دودویی، Crystal بهطور خودکار یک نمایش هشتهشتی را به Int32 تبدیل میکند.
0o123
# => 83
اگر به عددی که در دستگاه هشتهشتی نیست پیشوند 0o بدهید، خطای کامپایل ایجاد میشود.
مانند دودویی، میتوانیم از متد <int>.to_s(base) برای تبدیل یک Int32 به نمایش هشتهشتی استفاده کنیم.
و میتوانیم از متد <int>.to_i(base) برای تبدیل یک نمایش هشتهشتی به Int32 استفاده کنیم.
83.to_s(8)
# => "123"
"123".to_i(8)
# => 83
مانند دودویی، اگر مبنای نادرست بدهید، خطای ArgumentError ایجاد میشود.
شانزدهشانزدهی یک دستگاه اعداد با مبنای ۱۶ است. از رقمهای ۰ تا ۹ و حروف A، B، C، D، E و F استفاده میکند. A برابر ۱۰ است، B برابر ۱۱، C برابر ۱۲، D برابر ۱۳، E برابر ۱۴ و F برابر ۱۵.
میتوانیم عددهای شانزدهشانزدهی را در Crystal با پیشوند 0x نمایش دهیم.
مانند دودویی و هشتهشتی، Crystal لیترالهای شانزدهشانزدهی را بهطور خودکار به Int32 تبدیل میکند.
#=> 0x123
291
اگر به عددی که شانزدهشانزدهی نیست پیشوند 0x بدهید، خطای کامپایل ایجاد میشود.
مانند دودویی، میتوانیم از متد <int>.to_s(base) برای تبدیل یک Int32 به نمایش شانزدهشانزدهی استفاده کنیم.
و میتوانیم از متد <int>.to_i(base) برای تبدیل یک نمایش شانزدهشانزدهی به Int32 استفاده کنیم.
291.to_s(16)
# => "123"
"123".to_i(16)
# => 291
مانند دودویی و هشتهشتی، اگر مبنای نادرست بدهید، خطای ArgumentError ایجاد میشود.
هنگام تبدیل یک عدد به نمایش رشتهای، میتوانیم دقت عدد را مشخص کنیم.
یعنی کمترین تعداد رقمهایی که برای نمایش عدد به کار میرود.
اگر رقمهای عدد از دقت کمتر باشد، صفرهای ابتدایی به نمایش رشتهای اضافه میشوند.
این کار با دادن آرگومان precision به متد <int>.to_s(<base>, precision: <value>) انجام میشود.
291.to_s(16, precision: 5)
# => "00123"
543.to_s(precision: 2)
# => "543"
دوستتان از پرداخت پول برای نرمافزار ویرایش عکس خسته شده و تصمیم گرفته خودش یکی بنویسد. دوستتان تصمیم گرفته اسم نرمافزار جدید را Foto Fusionist بگذارد.
Foto Fusionist یک نرمافزار ویرایش عکس است که میتواند کارهای زیادی انجام دهد، اما شما تا اینجا فقط چند مورد از آنها را پیادهسازی کردهاید. با این حال، دوستتان از پیشرفت خیلی خوشحال است و از شما خواسته چند قابلیت دیگر را هم پیادهسازی کنید.
برای اولین قابلیت، دوستتان میخواهد بتواند نمایش دودویی یک عدد را به عدد صحیح تبدیل کند. این کار لازم است چون نرمافزار باید بتواند نمایش دودویی یک کانال رنگی را بخواند و آن را به عدد صحیح تبدیل کند.
متد FotoFusionist.binary_to_int را پیادهسازی کنید که یک آرگومان به اسم binary از نوع String میگیرد.
این متد باید معادل عدد صحیح عدد دودویی را برگرداند.
FotoFusionist.binary_to_int("10011")
# => 19
دومین قابلیتی که دوستتان میخواهد این است که بتواند کمارزشترین بیت را از یک عدد صحیح بگیرد. «کمارزشترین بیت» بیتی است که در سمت راستترین نقطه قرار دارد. به این دلیل کمارزشترین بیت نامیده میشود که کمترین ارزش را دارد.
از کمارزشترین بیت برای این استفاده میشود که ارزیابی کنیم آیا میتوان تصویر را با کاهش تعداد بیتهایی که برای نمایش کانال رنگی به کار میرود بهینه کرد یا نه.
متد FotoFusionist.least_significant_bit را پیادهسازی کنید که یک آرگومان به اسم number از نوع Int32 میگیرد.
این متد باید کمارزشترین بیت عدد را برگرداند.
FotoFusionist.least_significant_bit(0b10011)
# => 1
FotoFusionist.least_significant_bit(0b10010)
# => 0
سومین قابلیتی که دوستتان میخواهد این است که بتواند «مقدار هگزادسیمال» را از یک کانال رنگی بگیرد. مقدار هگزادسیمال لازم است تا بتوان کانال رنگی را به یک نمایش هگزادسیمال تبدیل کرد و این نمایش هگزادسیمال باید از دو رقم تشکیل شده باشد.
متد FotoFusionist.hex_value را پیادهسازی کنید که یک آرگومان به اسم number از نوع Int32 میگیرد.
این متد باید مقدار هگزادسیمال عدد را بهصورت یک String برگرداند.
FotoFusionist.hex_value(19)
# => "13"
چهارمین قابلیتی که دوستتان میخواهد این است که بتواند مقدار هگزادسیمال را از یک رنگ RGB بگیرد. این کار لازم است تا کاربر بتواند یک نمایش رشتهای واحد از یک رنگ به دست آورد. رنگ RGB رنگی است که با سه کانال رنگی نمایش داده میشود: قرمز، سبز و آبی. هر کانال رنگی با عددی بین ۰ و ۲۵۵ نمایش داده میشود.
مقدار هگزادسیمال یک رنگ RGB، نمایش رشتهای آن رنگ در مبنای شانزده است، به این ترتیب که اول کانال رنگی قرمز، بعد کانال رنگی سبز و در آخر کانال رنگی آبی میآید.
متد FotoFusionist.hex_value_from_rgb را پیادهسازی کنید که سه آرگومان میگیرد: red، green و blue از نوع Int32.
این متد باید مقدار هگزادسیمال رنگ RGB را بهصورت یک String برگرداند.
FotoFusionist.hex_value_from_rgb(255, 0, 0)
# => "ff0000"