Julia یک زبان همهمنظوره است که میتوان از آن برای بیشتر کارهای برنامهنویسی استفاده کرد. اما در عمل، کاربردهای اصلی آن بیشتر در مهندسی و علوم است. محاسبات عددی سریع، انعطافپذیر و پیشرفته، نقش محوری در طراحی آن دارند.
عدد صحیح یک عدد «گرد» است که نقطهی اعشار ندارد.
در مفهوم مبانی دیدیم که میتوان یک مقدار صحیح را بدون تعیین نوع به یک متغیر اختصاص داد.
برای خوانایی، میتوان از زیرخط به عنوان جداکنندهی ارقام استفاده کرد. کامپایلر آنها را نادیده میگیرد.
julia> x = 3
3
julia> typeof(x)
Int64
julia> large_number = 1_234_567_890
1234567890
تعجبی ندارد که اعداد اعشاری یک نقطهی اعشار و بخشی کسری پس از آن داشته باشند.
julia> f = 3.45
3.45
julia> typeof(f)
Float64
البته نماد علمی هم پشتیبانی میشود.
julia> avogadro = 6.02e23
6.02e23
شاید بیشینه و کمینهی مقادیر غافلگیرکننده باشند:
julia> typemax(Float64)
Inf
julia> typemin(Float64)
-Inf
بینهایت یک مقدار معتبر است!
همانطور که در مفهوم مبانی بحث شد، عملگرهای حسابی تقریباً مانند حساب معمولی عمل میکنند، همان حسابی که در مدرسه به کودکان آموزش داده میشود.
توجه کنید که توان از ^ استفاده میکند، نه ** (هر دو در زبانهای دیگر رایجاند).
2 + 3 # 5 (addition)
2 - 3 # -1 (subtraction)
2 * 3 # 6 (multiplication)
8 / 2 # 4.0 (division)
8 % 3 # 2 (remainder)
2 ^ 3 # 8 (exponentiation)
با این حال، چند نکتهی خاص Julia هست که ارزش پرداختن دارد.
julia> x = 4.2
4.2
julia> 2 * x
8.4
julia> 2x
8.4
julia> 2.4x
10.08
این ممکن است غافلگیرکننده باشد.
همیشه میتوان از * به عنوان عملگر میانوندی استفاده کرد، مانند بیشتر زبانهای برنامهنویسی دیگر.
اما Julia را کسانی طراحی کردهاند که باور دارند کد باید تا حد امکان شبیه معادلات ریاضی به نظر برسد.
چون اسم متغیرها باید با یک حرف شروع شود، قرار دادن یک عدد (صحیح یا اعشاری) پیش از اسم، ضرب ضمنی در نظر گرفته میشود.
برای مثال، اگر مساحت سطح یک کره را بخواهیم، به جای 4 * pi * r * r میتوانیم این کار را بکنیم:
julia> surface(r) = 4π * r^2
surface (generic function with 1 method)
julia> surface(3)
113.09733552923255
هرچند π یک ثابت از پیش تعریفشده است، یک حرف (یونانی) هم هست.
بنابراین تجزیهگر هنوز به یک * صریح نیاز دارد تا π را از r جدا کند.
استفاده از / به عنوان عملگر میانوندی همیشه یک نتیجهی اعشاری میدهد، حتی برای ورودیهای صحیح.
برای تقسیم صحیح، گزینههای بیشتری وجود دارد.
julia> 10 / 3 # floating-point division
3.3333333333333335
julia> div(10, 3) # integer division
3
julia> 10 ÷ 3 # synonym for div()
3
julia> 10 // 3 # rational number (fraction)
10//3
تابع div() برای تقسیم صحیح است و نتیجهاش به سمت صفر بریده میشود: برای اعداد مثبت به پایین و برای اعداد منفی به بالا.
به عنوان مترادف، میتوانیم از عملگر میانوندی ÷ استفاده کنیم، باز هم با این هدف که ریاضیتر به نظر برسد.
اگر از ویرایشگری استفاده میکنید که Julia را میشناسد، آن را به صورت \div وارد کنید و بعد کلید <Tab> را بزنید.
عملگر // فراتر از حوزهی این مفهوم است.
فعلاً میتوانیم فقط بگوییم که نتیجهی // یک عدد «گویا» است، همان چیزی که بیشتر مردم کسر مینامند.
این کار اغلب میتواند خودکار انجام شود:
julia> x = 2 + 3.5
5.5
julia> typeof(x)
Float64
یک Int64 را به یک Float64 اضافه کردیم و نتیجهی Float64 گرفتیم.
در واقع، عدد صحیح بیصدا به Float64 تبدیل شد و بعد جمع انجام گرفت.
تبدیلهای اعشاری به صحیح ناگزیر پیچیدهترند. با بخشی که پس از نقطهی اعشار میآید چه میخواهید بکنید؟
round() به نزدیکترین عدد صحیح گرد میکند؛ وقتی عددی مانند ۴.۵ دقیقاً وسط دو عدد صحیح باشد، به نزدیکترین عدد صحیح زوج گرد میشود.floor() به پایین گرد میکند، ceil() به بالا و trunc() به سمت صفر.Int32()، با خطای InexactError شکست میخورد.اما این توابع به طور پیشفرض نوع صحیحی را که ممکن است میخواستید برنمیگردانند. میتوان نوع خروجی دلخواه را مشخص کرد.
julia> round(4.5)
4.0
julia> ceil(Int, 4.3)
5
گرد کردن به تعداد مشخصی رقم پس از نقطهی اعشار هم با کلیدواژهی digits امکانپذیر است.
julia> round(π, digits=10)
3.1415926536
حتماً این فقط یک خطا ایجاد میکند؟ در واقع، ماجرا آنقدرها هم ساده نیست.
تقسیم صحیح با ÷ یا // همانطور که انتظار دارید به خطا میانجامد.
تقسیم اعشاری با / رویکردی را در پیش میگیرد که میتوان آن را رویکردی مهندسی دانست، نه رویکرد استاندارد علوم کامپیوتر:
julia> 2 / 0
Inf
julia> 0 / 0
NaN
همانطور که در بخش قبلی بحث شد، بینهایت در Julia یک عدد اعشاری معتبر است که با Inf نشان داده میشود.
وقتی صورت کسر هم صفر باشد، نتیجه از نظر ریاضی تعریفنشده است.
در این حالت Julia آن را «عدد نیست» در نظر میگیرد که با NaN نشان داده میشود.
دوست شما، چندلر، قصد دارد به کشورهای عجیب و غریب در سراسر جهان سفر کند. متأسفانه مهارتهای ریاضی چندلر خوب نیست. او خیلی نگران است که در طول سفر، صرافیها سرش کلاه بگذارند، و از شما میخواهد که یک ماشینحساب ارز برایش بسازید. این هم مشخصات او برای این برنامه:
تابع exchange_money() را بسازید که ۲ پارامتر میگیرد:
budget : مبلغی که قصد دارید تبدیل کنید.exchange_rate : مقدار ارز داخلی که برابر با یک واحد ارز خارجی است.این تابع باید ارزش ارز تبدیلشده را برگرداند.
توجه: اگر ارز شما USD است و میخواهید USD را با نرخ تبدیل 1.20 به EUR تبدیل کنید، آنگاه 1.20 USD == 1 EUR.
julia> exchange_money(127.5, 1.2)
106.25
تابع get_change() را بسازید که ۲ پارامتر میگیرد:
budget : مبلغ پول پیش از تبدیل.exchanging_value : مبلغی که از بودجه برداشت میشود تا تبدیل شود.این تابع باید مبلغی را برگرداند که از بودجه باقی میماند.
julia> get_change(127.5, 120)
7.5
تابع get_value_of_bills() را بسازید که ۲ پارامتر میگیرد:
denomination : ارزش یک اسکناس.number_of_bills : تعداد کل اسکناسها.این باجهی تبدیل ارز فقط با پول نقدی با مضارب مشخص سروکار دارد. مبلغی که دریافت میکنید باید بر ارزش یک «اسکناس» یا واحد بخشپذیر باشد، که میتواند کسری یا باقیماندهای بر جای بگذارد. تابع شما باید فقط ارزش کل اسکناسهایی را برگرداند (بدون مقادیر کسری) که باجه پس میدهد. متأسفانه باجه میتواند باقیمانده/خرد را به عنوان سود اضافه برای خودش نگه دارد.
julia> get_value_of_bills(5, 128)
640
تابع get_number_of_bills() را بسازید که amount و denomination را میگیرد.
این تابع باید تعداد اسکناسهای ارز را برگرداند که میتوانید در محدودهی amount دادهشده دریافت کنید. به بیان دیگر: چند اسکناس کامل در مبلغ اولیه جا میگیرد؟ یادتان باشد که فقط میتوانید اسکناس کامل دریافت کنید، نه کسری از اسکناس، پس تقسیم را بر همین اساس انجام دهید. در واقع دارید به نزدیکترین اسکناس/واحد کامل به پایین گرد میکنید.
julia> get_number_of_bills(127.5, 5)
25
تابع get_leftover_of_bills() را بسازید که amount و denomination را میگیرد.
این تابع باید مبلغ باقیمانده را برگرداند؛ مبلغی که با توجه به واحد اسکناسها نمیتوان از amount اولیهی شما پس داد. دانستن اینکه باجه دقیقاً چقدر را برای خودش نگه میدارد بسیار مهم است.
julia> get_leftover_of_bills(127.5, 20)
7.5
تابع exchangeable_value() را بسازید که budget، exchange_rate، spread و denomination را میگیرد.
پارامتر spread درصدی است که به عنوان کارمزد تبدیل گرفته میشود و به صورت یک عدد صحیح نوشته شده است.
باید آن را با تقسیم بر ۱۰۰ به عدد اعشاری تبدیل کنید.
اگر 1.00 EUR == 1.20 USD باشد و spread برابر 10، نرخ تبدیل کل در واقع چنین خواهد بود: 1.00 EUR == 1.32 USD، چون ۱۰٪ از ۱٫۲۰ برابر ۰٫۱۲ است و این کارمزد اضافه به تبدیل افزوده میشود.
این تابع باید بیشترین ارزش ارز جدید را پس از محاسبهی نرخ تبدیل بهعلاوهی spread برگرداند. یادتان باشد که واحد ارز یک عدد کامل است و نمیتواند تقسیم شود.
توجه: مقدار بازگشتی باید از نوع عدد صحیح باشد.
julia> exchangeable_value(127.25, 1.20, 10, 20)
80
julia> exchangeable_value(127.25, 1.20, 10, 5)
95