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 的數學不太好。他很擔心旅途中被貨幣兌換處坑錢,所以希望你能幫他做一個貨幣計算器。以下是他對這個應用程式的需求:
建立exchange_money()函式,接受 2 個參數:
budget:你打算兌換的金額。exchange_rate:等於一單位外幣的本國貨幣金額。這個函式應該回傳兌換後貨幣的價值。
注意: 如果你的貨幣是 USD,而你想用1.20的匯率把 USD 兌換成 EUR,那麼1.20 USD == 1 EUR。
julia> exchange_money(127.5, 1.2)
106.25
建立get_change()函式,接受 2 個參數:
budget:兌換前的金額。exchanging_value:從預算中取出用來兌換的金額。這個函式應該回傳預算中剩下的金額。
julia> get_change(127.5, 120)
7.5
建立get_value_of_bills()函式,接受 2 個參數:
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是作為兌換手續費收取的百分比,以整數表示。
它需要除以 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