學習軌道
/
Julia
Julia
/
練習
/
貨幣兌換
貨幣兌換

貨幣兌換

學習練習

簡介

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()函式會四捨五入到最接近的整數;遇到像 4.5 這種正好在中間的情況時,會捨入到最接近的_偶數_。
  • 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表示。

說明

你的朋友 Chandler 打算走訪世界各地充滿異國風情的國家。可惜的是,Chandler 的數學不太好。他很擔心旅途中被貨幣兌換處坑錢,所以希望你能幫他做一個貨幣計算器。以下是他對這個應用程式的需求:

1. 估算兌換後的價值

建立exchange_money()函式,接受 2 個參數:

  1. budget:你打算兌換的金額。
  2. exchange_rate:等於一單位外幣的本國貨幣金額。

這個函式應該回傳兌換後貨幣的價值。

注意: 如果你的貨幣是 USD,而你想用1.20的匯率把 USD 兌換成 EUR,那麼1.20 USD == 1 EUR。

julia> exchange_money(127.5, 1.2)
106.25

2. 計算兌換後剩下的金額

建立get_change()函式,接受 2 個參數:

  1. budget:兌換前的金額。
  2. exchanging_value:從預算中取出用來兌換的金額。

這個函式應該回傳預算中剩下的金額。

julia> get_change(127.5, 120)
7.5

3. 計算紙鈔的價值

建立get_value_of_bills()函式,接受 2 個參數:

  1. denomination:單張紙鈔的價值。
  2. number_of_bills:紙鈔的總張數。

這間兌換亭只以特定面額單位的現金進行交易。 你收到的總額必須能被一張「紙鈔」(也就是一個單位)的價值整除,除不盡的部分會留下零頭或餘數。 你的函式應該只回傳兌換亭會還給你的紙鈔總價值(不包含零頭)。 可惜的是,剩下的零頭就當作額外的好處,留給兌換亭。

julia> get_value_of_bills(5, 128)
640

4. 計算紙鈔的張數

建立get_number_of_bills()函式,接受amount和denomination。

這個函式應該回傳在給定的_amount_內你能拿到多少張_紙鈔_。 換句話說:起始金額能放進幾張_完整的紙鈔_? 記住,你只能拿到_完整的紙鈔_,不能拿到紙鈔的一小部分,所以記得要正確地相除。 實際上,你就是把金額_向下_取整到最接近的整張紙鈔(面額)。

julia> get_number_of_bills(127.5, 5)
25

5. 計算換成紙鈔後的剩餘金額

建立get_leftover_of_bills()函式,接受amount和denomination。

這個函式應該回傳在給定的紙鈔面額下,起始_amount_中無法換回的_剩餘金額_。 確切知道兌換亭能留下多少錢非常重要。

julia> get_leftover_of_bills(127.5, 20)
7.5

6. 計算兌換後的價值

建立exchangeable_value()函式,接受budget、exchange_rate、spread和denomination。

參數spread是作為兌換手續費收取的百分比,以整數表示。 它需要除以 100 轉換成小數。 如果1.00 EUR == 1.20 USD,而spread是10,那麼實際的總匯率會是:1.00 EUR == 1.32 USD,因為 1.20 的 10% 是 0.12,而這筆額外費用會加到匯率上。

這個函式應該在計算匯率加上spread之後,回傳新貨幣的最大價值。 記住,貨幣的denomination是整數,不能分割。

注意: 回傳值應該是整數型別。

julia> exchangeable_value(127.25, 1.20, 10, 20)
80

julia> exchangeable_value(127.25, 1.20, 10, 5)
95
透過 GitHub 編輯 連結會在新視窗或分頁中開啟
Julia Exercism

準備好開始 貨幣兌換 了嗎?

註冊 Exercism,透過 35 個概念128 個練習 和真人引導來學習並精通 Julia,全部免費。