2019年5月20日

Types and Dispatch in juila

julia 同樣也有 type system 處理 Types, Data Types,可識別 integer, string, float, Boolean。

Type system

types 是什麼?
1
1.1
'j'
"julia"

這些資料都可以直接識別出差異,分別是 integer, float, char, string。但需要一個方法讓電腦能夠識別這些資料型別。

static type vs dynamic type

有兩種方法可告訴 interpreter 資料型別是什麼

static type: 直接標記出資料型別,例如 C, C++, Java

dynamic type: interpreter 在 runitme 自動判斷資料型別,例如 Perl, Python, Ruby。雖然不指定,但內部還是會將該資料,標記為某一個資料型別

julia 同時有 static type 及 dynamic type 的功能。如果使用 static type,會讓程式運作地比較快。

Type annotations

討論 type declaration 及 conversion

:: Int64 就是將變數定義為 Int64 這個資料型別

julia> function cube(number::Int64)
        return number ^ 3
       end
cube (generic function with 1 method)

julia> cube(3)
27

實際上 :: 是個 operator,也很類似 python 的 isinstance()

julia> 2::Int64
2

julia> 2::Float64
ERROR: TypeError: in typeassert, expected Float64, got Int64

  • typeof(): type of data
  • typemax(): 該 type 可支援的最大 value
  • typemin(): 該 type 可支援的最小 value
  • bitstring(): 二進位的位元字串

  • Integer type 會根據使用的機器不同,可能是 Int8, Int16, Int32, Int64, or Int128 其中一種

    julia> typeof(1)
    Int64
    
    julia> typemax(Int64)
    9223372036854775807
    
    julia> typemin(Int64)
    -9223372036854775808
  • Float type 在 64bits 機器,是 Float64

    julia> typeof(1.1)
    Float64
    
    julia> typemax(Float64)
    Inf
    
    julia> typemin(Float64)
    -Inf
  • Char type

  • String type

  • Bool type


isa(x, type) -> Bool 判斷 x 資料型別是否為 type

julia> isa(5, Int64)
true

julia> isa(5.5, Float64)
true

type conversions

convert(type, x) 可將 x 轉換資料型別為 type

julia> convert(Float64, 10)
10.0

julia> convert(Int64, 128.0)
128

julia> convert(Int64, 128.3)
ERROR: InexactError: Int64(Int64, 128.3)
Stacktrace:
 [1] Type at ./float.jl:700 [inlined]
 [2] convert(::Type{Int64}, ::Float64) at ./number.jl:7
 [3] top-level scope at none:0

rounding: ceil, floor, round

julia> ceil(Int, 3.4)
4

julia> floor(Int, 3.4)
3

julia> round(Int, 3.4)
3

julia> round(Int, 3.6)
4

subtypes and supertypes

Number 是 Any 的 subtype,Any 是 Number 的 supertype

                      Any
                       |
     ---------------------------------------------
     Number                          AbstractString
        |                                   |
----------------                            |
Complex       Real                          |
                                            |
                                            |
         ----------------------------------------------------------
        |           |           |                     |            |
UTF8String    UTF16String     DirectIndexString   RepString    RopeString

Any 是所有資料型別的起點

julia> supertype(Number)
Any

julia> supertype(Any)
Any

julia> typeof(Any)
DataType

julia> subtypes(Number)
2-element Array{Any,1}:
 Complex
 Real

recursive 找出所有子類別

julia> function check_all_subtypes(T, space=0)
                  println("\t" ^ space, T)
                  for t in subtypes(T)
                      if t!= Any
                      check_all_subtypes(t, space+1)
                  end
              end
              end
check_all_subtypes (generic function with 2 methods)

julia> check_all_subtypes(Number)
Number
    Complex
    Real
        AbstractFloat
            BigFloat
            Float16
            Float32
            Float64
        AbstractIrrational
            Irrational
        Integer
            Bool
            Signed
                BigInt
                Int128
                Int16
                Int32
                Int64
                Int8
            Unsigned
                UInt128
                UInt16
                UInt32
                UInt64
                UInt8
        Rational

User-defined and composite data types

可自訂資料型別: use abstract|primitive type, struct, mutable struct for type definitions

ref: crazy idea: change the type keyword

julia> struct Person
           name::String
           age::Int64
       end

julia> typeof(Person)
DataType

julia> a = Person("Name", 10)
Person("Name", 10)

julia> typeof(a)
Person

julia> a.name
"Name"

julia> a.name = "name2"
ERROR: type Person is immutable

檢查自訂資料型別的層級

julia> supertype(Person)
Any

julia> subtypes(Person)
0-element Array{Type,1}

julia> fieldnames(Person)
(:name, :age)

julia> typeof(:name)
Symbol

composite types

剛剛的 Person 資料無法修改,使用 mutable struct 就可以變成可修改的資料型別

julia> mutable struct Point
           x :: Int64
           y :: Int64
           z :: Int64
       end

julia> p = Point(1,2,3)
Point(1, 2, 3)

julia> p.x=10
10

julia> p
Point(10, 2, 3)

Inner constructor

剛剛的 struct,可在 constructor 中,增加資料的檢查,確認新的物件符合資料型別設計的條件

julia> struct Family
          num_members :: Int64
          members :: Array{String, 1}

          # inner constructor in play
          Family(num_members, members) = num_members != length(members) ? error("Mismatch!!") : new(num_members, members)
       end

julia> f1 = Family(1, ["husband", "wife"])
ERROR: Mismatch!!
Stacktrace:
 [1] error(::String) at ./error.jl:33
 [2] Family(::Int64, ::Array{String,1}) at ./REPL[14]:6
 [3] top-level scope at none:0

julia> f2 = Family(2, ["husband", "wife"])
Family(2, ["husband", "wife"])

Modules and interfaces

julia 的 namespaces,可讓我們建立 top-level global variable,但又不會在所有程式中互相衝突。

module SampleModule
..
..
end
julia> module MyModule
                  foo=10
                  bar=20
                  function baz()
                      "baz"
                  end
                  function qux()
                      "qux"
                  end
                  export foo, baz
                  end
Main.MyModule

julia> MyModule.bar
20

using MyModule 跟 import MyModule 的差異

  • using MyModule,會將所有 exported functions 都帶入目前的 scope,等於是宣告 MyModule.foo,可以這樣使用 MyModule:foo
  • import MyModule,將 functions 匯入目前的 scope,只能取得 exported functions/variables,就無法使用 foo

Including files in modules

當 module, package 分散在多個檔案中,使用 include 彙整

# 按下 ; 進入 shell
# transformations.jl 是獨立的檔案
shell> cat transformations.jl
function say_hello(name:: String)
    "hello, $name"
end
julia> include("transformations.jl")
say_hello (generic function with 1 method)

julia> say_hello("rahul")
"hello, rahul"

Module file paths

通常用 using SomeModule 時,julia 會尋找預設 module 路徑

可用 push! 增加 library 路徑,或是設定環境變數 JULIA_LOAD_PATH

julia> push!(LOAD_PATH, "~/Downloads/Module/")
4-element Array{String,1}:
 "@"
 "@v#.#"
 "@stdlib"
 "~/Downloads/Module/"

module precompilation

在使用某個 module 時,會先花一些時間進行編譯,如果有編譯完成的,才會直接匯入

目前 1.0 版,所有 modules 都是enable precompilation

Samplecode.jl

module Samplecode

export sum_of_numbers

sum_of_numbers = 0
for num in 1:10000
    global sum_of_numbers += num
end

end
julia> push!(LOAD_PATH, "~/path/")
4-element Array{String,1}:
 "@"
 "@v#.#"
 "@stdlib"
 "~/path/"

julia> @time using Samplecode
[ Info: Precompiling Samplecode [top-level]
  1.343508 seconds (1.13 M allocations: 55.605 MiB, 0.38% gc time)

julia> @time using Samplecode
  0.000552 seconds (782 allocations: 42.547 KiB)

multiple dispatch

julia> struct Coordinate{T}
                  x::T
                  y::T
                  z::T
              end

julia> function calc_sum(value::Coordinate{Int64})
                  value.x + value.y + value.z
              end
calc_sum (generic function with 1 method)

julia> function calc_sum(value::Coordinate{Float64})
                         value.x + value.y + value.z
              end
calc_sum (generic function with 2 methods)

julia> methods(calc_sum)
# 2 methods for generic function "calc_sum":
[1] calc_sum(value::Coordinate{Float64}) in Main at REPL[6]:2
[2] calc_sum(value::Coordinate{Int64}) in Main at REPL[5]:2

julia> calc_sum(Coordinate(1,2,3))
6

julia> calc_sum(Coordinate(1.0,2.0,3.0))
6.0

References

Learning Julia

2019年5月13日

Functions in Julia

Creating Functions

function 的定義:an object that maps a tuple of arguments values to a return value

julia> function greet()
           println("hello world")
       end
greet (generic function with 1 method)

julia> greet()
hello world
        
julia> function calculator(x, y, operation)
           if operation == "+"
               x+y
           elseif operation == "-"
               x-y
           elseif operation == "*"
               x*y
           elseif operation == "/"
               x/y
           else
               println("Incorrect operation")
               return 0
           end
       end
calculator (generic function with 1 method)

julia> println(calculator(10,20, "+"))
30

julia> println(calculator(10,20, "*"))
200

如果在 function 名稱最後面看到 ! 這個符號,這是 julia 的命名習慣,這表示這個 function 會修改 input 的參數資料內容,例如 push!

julia> push!([1,2,3], 4)
4-element Array{Int64,1}:
 1
 2
 3
 4

Function Argurments

通常參數是以 pass by value 或是 pass by reference 的方式處理,但 julia 是使用 pass by sharing 的方式。

pass by value: 傳入 function 的參數,會複製數值,這表示該變數會產生 2 copies

pass by reference: function 的參數,會使用該變數的 reference,該變數只有 1 copy

pass by sharing: 傳入 function 的變數,不會被複製。參數本身只是一個新的 binding,參考到原本變數的值。這也很像是 pass by value,只是那個 value 是 object reference。

ref: 深入探討 JavaScript 中的參數傳遞:call by value 還是 reference?

以 function 內對參數重新賦值,外面的變數如果也會改變,就是 pass by reference。如果不會改變就是 pass by value,在 pass by value 的條件下,如果可以透過變數,修改 function 外面的變數的值,就是 pass by sharing。


return keyword

return 用來結束 function 執行,julia 的 function 可使用或不使用 return,如果 function 沒有 return,就表示會回傳最後一個 statement 的運算結果。

julia> function add_without_return(x,y)
               x+y
       end
add_without_return (generic function with 1 method)

julia> function add_using_return(x,y)
               return x+y
       end
add_using_return (generic function with 1 method)

julia> add_without_return(20,30) == add_using_return(20,30)
true

arguments

傳入的參數,可以不指定資料型別,也可以限制資料型別。限制資料型別,可讓 compiler 介入並最佳化編譯結果。

function say_hello(name)
    println("hello $name")
end
say_hello("world")

function say_hello(name::String)
    println("hello $name")
end
say_hello("world")

function 可以沒有任何參數

julia> function does_nothing
       end
does_nothing (generic function with 0 methods)

varargs 是 variable arguments,不定長度的參數,julia 是使用 ...

傳入三個參數,第一個獨立,第2,3 個參數,在 function 裡面是對應為 y...,所以 y 是 tuple

julia> function letsplay(x,y...)
           println(x)
           println(y)
       end
letsplay (generic function with 1 method)

julia> letsplay("cricket","hockey","tennis")
cricket
("hockey", "tennis")

傳入 function 的變數,可以在定義 function 前,就先宣告該變數


x = (1,2,3,4,5)
y = (6,7,8)

function numbers(a...)
    println("the arguments x are -> ", x)
    println("the arguments a are -> ", a)
end

numbers(y)
# the arguments x are -> (1, 2, 3, 4, 5)
# the arguments a are -> ((6, 7, 8),)

x = [1,2,3,4,5]
y = [6,7,8]

numbers(y)
# the arguments x are -> [1, 2, 3, 4, 5]
# the arguments a are -> ([6, 7, 8],)

optional arguments

function 中有些參數已經有預設值,呼叫該 function 就不需要傳入該參數

function f(x, y=4, z=10)
    x+y+z
end

f(10)
# 24

variable scope

julia 有兩個主要的 scope: global, local

module 內或是 REPL 內的變數,通常是 global scope。loops, functions, macros, try-catch-finally block 裡面的變數是 local scope。

如果刻意加上 global,可讓變數變成 global scope

julia> for i=1:5
               global hello
               hello = i
       end

julia> hello
5

lexical scoping: funtion 的 scope 不會繼承 caller's scope,而是由 function 定義的時候開始。例如 module 內定義了 name 變數,後面又定義了另一個 name,當呼叫 module 內的 method,使用的 name 變數,是一開始在 module 內定義的 name。

julia> module Utility
               name = "Julia"
               tell_name() = name
       end
Main.Utility

julia> name = "Python"
"Python"

julia> Utility.tell_name()
"Julia"

julia 將 local scope 分為 soft 及 hard local scope,function 裡面是 hard local scope。


nested functions

* 如果是兩個整數,就是整數相加,如果是兩個字串,則是將字串連接在一起

julia> function outer(value_a)
               function inner(value_b)
                       return value_a * value_b
               end
       end
outer (generic function with 1 method)

# 回傳一個 function
julia> result = outer(10)
(::getfield(Main, Symbol("#inner#3")){Int64}) (generic function with 1 method)

julia> typeof(result)
getfield(Main, Symbol("#inner#3")){Int64}

julia> result(10)
100

julia> result = outer("learning ")
(::getfield(Main, Symbol("#inner#3")){String}) (generic function with 1 method)

julia> result("Julia")
"learning Julia"

Anonymous Functions

也可稱為 lambda functions

語法:f -> 2f

map() 的第一個參數,需要傳入一個 function,可使用 anonymous function

julia> map(f -> 2f, [2, 3])
2-element Array{Int64,1}:
 4
 6

julia> map(f -> 2f, [2 3])
1×2 Array{Int64,2}:
 4  6

julia> map((f,g) -> 2f + 2g, [2,3], [3,4])
2-element Array{Int64,1}:
 10
 14

Multiple Dispatch

dispatch 就是 to send 的意思,也就是 send a message to a listener,或是 call to a function

dispatch 有以下形式

  • static dispatch

    在 compile time 定義 dispatch order,在執行程式前,就已經知道所有資料型別。compiler 能夠對所有可能的資料型別的組合,都產生對應的程式碼,並預先知道什麼時候在哪裡被使用。這是程式語言中最常見的形式。

    可用 funct() 或是 x.functiont() 呼叫 function / method,每次呼叫時都是固定不變的。

  • dynamic dispatch

    runtime 定義 dispatch order。compiler 會產生所有 functions 的 lookup table,在 runtime 決定要呼叫哪一個 function。

    例如有 classA, classB 都有 foo() function,runtime 時,兩個 class 都會被檢查到有 foo(),可能或呼叫 classA.foo() 或是 classB.foo() 任一個 function

  • multiple dispatch

    dispatch order 跟 function name 以及 argument types 有關,runtime 決定使用的 signature of the function 以及 actual implementation。

    classA 有 foo(int) 以及 foo(char) ,當呼叫 classA.foo(x) 時,在 runtime 會檢查 classA 及 x,然後決定要使用哪一個 function

julia 使用 multiple dispatch


Understanding methods

尋找適當的函數,同時會檢查參數的資料型別

function add_numbers(num1::Int64, num2::Int64)
    return num1 + num2
end

add_numbers(10,20)

add_numbers(10.0,20.0)
# ERROR: MethodError: no method matching add_numbers(::Float64, ::Float64)

function add_numbers(num1::Float64, num2::Float64)
    return num1+num2
end

julia> methods(add_numbers)
# 2 methods for generic function "add_numbers":
[1] add_numbers(num1::Float64, num2::Float64) in Main at REPL[36]:2
[2] add_numbers(num1::Int64, num2::Int64) in Main at REPL[33]:2

如果要用一個 methd 同時支援多種資料型別,可以用類似 python 的做法,不指定參數的資料型別

function add_without_types(num1,num2)
    return num1+num2
end

add_without_types(10.0,20)

add_without_types(10,20.0)

Recursion

遞迴: 重複呼叫自己的 function

function generate_fibonacci(n::Int64)
    if n < 2
        return 1
    else
        return generate_fibonacci(n-1) + generate_fibonacci(n-2)
    end
end

# 另一種更簡單的寫法
generate_fibonacci(n) = n < 2 ? n : generate_fibonacci(n - 1) + generate_fibonacci(n - 2)

Built-in Functions

julia 的 base library 提供很多內建的 functions

  • workspace()

    只能在 REPL 使用,可以將目前 REPL 的所有資料清空

    note: 這個function 在 julia 1.0 已經不提供了

    ref: https://stackoverflow.com/questions/51872039/which-is-the-alternative-to-workspace-in-julia-1-0

  • typeof()

    查詢參數的資料型別

  • methods()

    查詢所有提供該 method 的 functions

    julia> methods(+)
    # 163 methods for generic function "+":
    [1] +(x::Bool, z::Complex{Bool}) in Base at complex.jl:277
    [2] +(x::Bool, y::Bool) in Base at bool.jl:104
    ...
  • readline(), readlines()

    由 STDIN 讀取 user input,如果加上參數,則是自檔案讀取資料

    julia> name = readline()
    julia
    "julia"
    
    julia> readlines("file.txt")
    43-element Array{String,1}:
    ...
  • enumerate()

    用來 iterate over a collection

    julia> fruits = ["apple", "orange", "banana"]
    3-element Array{String,1}:
     "apple"
     "orange"
     "banana"
    
    julia> for (index,fruit) in enumerate(fruits)
                   println("$index -> $fruit")
           end
    1 -> apple
    2 -> orange
    3 -> banana
  • parse()

    用來 parse a string,轉換為 number parse(type, str; base) base 是代表幾進位

    julia> parse(Int, "2")
    2
    
    julia> parse(Float64, "2.2")
    2.2
    
    julia> parse(Int, "1234", base = 5)
    194

References

Learning Julia

2019年5月6日

Programming Concepts in Julia

julia 提供很多讓 data scientists , statisticians 使用的功能,也非常接近 MATLAB, Python, R 的語法。

Revisiting programming paradigms

有四種:

  1. Imperative: C

    sequential execution,可改變變數的值。是以 Von Neumann computer 概念發展的,有 reusable memory,可修改 state。

    優點:

    • 有效利用系統資源
    • 接近 machine language

    缺點:

    • 有些問題無法單純以遵循 order of statements 解決
    • 因為可修改 state,讓程式比較難被理解
    • debug 不直覺
    • 只能完成有限的抽象化
  2. Logical: Prolog

    也稱為 rule-based paradigm,程式會處理資料,建立 rules 的組合,提供 logical expression。沒有 function,以 relations 取代。 Y=f(x) 改為 r(X, Y)

    ex:

    male(X) // X is a male
    father(F,X) // F is father of X
    father(F,Y) // F is father of Y
    mother(M,X) // M is mother of X
    mother(M,Y) // M is mother of Y
    
    // The preceding relationship implies:
    brother(X,Y) // X is a brother of Y
  3. Functional: Haskell

    由數學概念發展而來,將所有subprogram 都視為 functions。function 可當參數,也可以回傳 function。可將 imperative paradigm 轉換為 functional paradigm。

    優點:

    • function 為高階抽象概念,減少錯誤。
    • 適合用在 parallel computation
    • value 為 non-mutable

    缺點:

    • 在需要很多 sequential activity 的狀況下會很複雜。使用 imperative / object-oriented 會比較洽當。
    • 程式可能會比較沒有效率
  4. Object-oriented: Smalltalk

    everythin is an object,可利用 behavior/method 修改物件的狀態 state

    有四個基本概念:

    • encapsulation
    • abstration
    • inheritance
    • polymorphism

Starting with Julia REPL

julia REPL 可直接執行 statements

$ julia -e 'println("HelloWorld")'
HelloWorld

$ julia -e 'for i=1:5; println("HelloWorld"); end'
HelloWorld
HelloWorld
HelloWorld
HelloWorld
HelloWorld

$ julia -e 'for i in ARGS; println(i); end' test1 test2 test3
test1
test2
test3

ARGS 可以取得 command line 參數

Variables

swap 變數

julia> x=24
24

julia> y=10
10

julia> x,y=y,x
(10, 24)

julia> x
10

可使用 unicode 變數名稱,或是以 _ 開頭

julia> 測試=100
100

julia> 測試
100

julia> _ab=40
40

pi 是內建的常數,不要用在自訂變數名稱

julia> pi
π = 3.1415926535897...

Naming Conventions

  • 通常變數名稱是小寫字母
  • 可使用 _ 但不建議使用
  • Function 及 macro 名稱是小寫字母
  • module 與 type 的第一個字母為大寫,名稱中不同的字,字首大寫: Upper Camel Case
  • 會修改/改寫參數(輸入資料)的 function,以 ! 結尾
a = Int64[]
push!(a, 1)    # => [1]
push!(a, 2)    # => [1,2]
push!(a, 3)    # => [1,2,3]
pop!(a)  # => 3
a # => [1,2]

可使用 typeof() 查詢變數的資料型別

julia> typeof(a)
Array{Int64,1}

numbers 可以用 _ 增加可讀性

julia> 100_000_000
100000000

julia> 1_0_0
100

Integers, bits, bytes, and bools

primitive numeric types

Type number of bits smallest values largest value
Int8 8 -2^7 2^7-1
UInt8 8 0 2^8-1
Int16 16 -2^15 2^15-1
UInt16 16 0 2^16-1
Int32 32 -2^31 2^31-1
UInt32 32 0 2^32-1
Int64 64 -2^63 2^63-1
UInt64 64 0 2^64-1
Int128 128 -2^127 2^127-1
UInt128 128 0 2^128-1
Bool 8 false(0) true(1)

可用 typemax, typemin 取得最大/最小值

julia> typemax(Int32)
2147483647

julia> typemin(Int32)
-2147483648

在 64bits 機器,數字預設型別為 Int64,也可用 Sys.WORD_SIZE (word size) 檢查機器的位元數

julia> typeof(10)
Int64
julia> Sys.WORD_SIZE
64

因為 julia 是 strong-type language,變數會維持原本的資料型別,在發生 overflowing 時,可能會取得錯誤的答案

julia> x = Int16(10000)
10000

julia> println(x*x)
-7936

julia> x=typemax(Int16)
32767

julia> x+Int16(1)
-32768

Bool 可用 true/false 為值, 0, NULL, empty string 不能視為 false

julia> 1>2
false

julia> typeof(ans)
Bool

julia> if 0
       println("hello")
       end
ERROR: TypeError: non-boolean (Int64) used in boolean context
Stacktrace:
 [1] top-level scope at none:0

Floating point number in Julia

type precision number of bits
Float16 half 16
Float32 single 32
Float64 double 64
julia> 100.0
100.0

julia> 24.
24.0

julia> .1
0.1

julia> typeof(ans)
Float64

julia> 0 == -0
true

julia> bitstring(0)
"0000000000000000000000000000000000000000000000000000000000000000"

julia> bitstring(-0)
"0000000000000000000000000000000000000000000000000000000000000000"

可使用 exponenital notation

julia> 2.99e8
2.99e8

julia> 2.99e8 > 99999
true

julia> 2.99f8
2.99f8

julia> 2.99e8 == 2.99f8
true

julia> typeof(2.99e8)
Float64

julia> typeof(2.99f8)
Float32

也可以使用 hexadecimal floating point literals,但只有 Float64

julia> 0x4.1p1
8.125

julia> typeof(ans)
Float64

Inf, -Inf, NaN

julia> 1/0
Inf

julia> -1/0
-Inf

julia> 0/0
NaN

julia> Inf/Inf
NaN

下(前)一個可以表示的 floating point number: nextfloat(), prevfloat()

julia> nextfloat(0.0)
5.0e-324

julia> prevfloat(0.0)
-5.0e-324

有時會遇到,計算結果跟預期的不同,這是因為該數字無法以正確的 floating-point representation 表示,就必須 rounded 到適當的 value。預設是 RoundNearest

julia> 0.1+0.2
0.30000000000000004
julia> 1.1+0.1
1.2000000000000002

這是因為 computer 無法正確表示 0.1, 0.2, 0.3 這樣的數字

ref: Strange behaviour when adding floating numbers

ref: What Every Programmer Should Know About Floating-Point Arithmetic


BigInt, BigFloat

julia 提供了不同精確度的計算方法。他使用了 GNU Multiple Precision Arithmetic Library, GMPGNU MPFR Library,並使用 BigInt, BigFloat 提供任意精確度的整數及浮點數。

julia> setrounding(BigFloat, RoundUp) do
                  BigFloat(1) + parse(BigFloat, "0.1")
              end
1.100000000000000000000000000000000000000000000000000000000000000000000000000003

julia> setrounding(BigFloat, RoundDown) do
                  BigFloat(1) + parse(BigFloat, "0.1")
              end
1.099999999999999999999999999999999999999999999999999999999999999999999999999986

julia> setprecision(40) do
                  BigFloat(1) + parse(BigFloat, "0.1")
              end
1.1000000000004

在寫數學方程式時,不需要特定寫 *

julia> x=4;y=5
5

julia> 3x+4y+5
37

Logical and arithmetic operations

+, -, *, /, ^, !, and %

julia> a=20;b=10
10

julia> a+b
30

julia> -a
-20

julia> !(4>2)
false

julia> -(-a)
20

bitwise operations

expression name
~x bitwise not
x & y bitwise and
x | y bitwise or
x ⊻ y bitwise xor
x >>> y logical shift right
x >> y arithmetic shift right
x << y logical/arithmetic shift left

+=, -=, *=, /=

julia> x=4
4

julia> x+=10
14

julia> x/=2
7.0

==, !=, <, <=, >, >=

julia> 100 > 99.99
true

julia> 24 == 24.0
true

julia> 24 === 24.0
false

julia> 24 !== 24.0
true

julia> NaN == NaN
false

julia> NaN === NaN
true

julia> Inf == Inf
true

julia> Inf >= NaN
false

可以 chain together

julia> 10 > 20 < 30 >= 30.0 == 100 > 101
false

precendence of operators 的執行順序

  1. Syntax (. followed by ::)
  2. Exponentiation (^)
  3. Fractions (//)
  4. Multiplication (*, /, %, &, and )
  5. Bitshifts (<<, >>, and >>>)
  6. Addition (+, -, |, and $)
  7. Syntax (:, .., and |>)
  8. Comparisons (>, <, >=, <=, ==, ===, !=, !==, and <:)
  9. Control flow (&& followed by || followed by ?)
  10. Assignments (=, +=, -=, *=, /=, //=, =, ^=, ÷=, %=, |=, &=, $=, <<=, >>=, and >>>=)

型別轉換

julia> Int8(100)
100

julia> Int8(100*10)
ERROR: InexactError: trunc(Int8, 1000)
Stacktrace:
 [1] throw_inexacterror(::Symbol, ::Any, ::Int64) at ./boot.jl:567
 [2] checked_trunc_sint at ./boot.jl:589 [inlined]
 [3] toInt8 at ./boot.jl:604 [inlined]
 [4] Int8(::Int64) at ./boot.jl:714
 [5] top-level scope at none:0

julia> Int16(100*10)
1000

Arrays and matrices

array 的 index 以 1 開始,不是 0。另外 array 的所有資料的型別都會是一樣的。

julia> a=[1,2,3,4]
4-element Array{Int64,1}:
 1
 2
 3
 4

julia> a[2]
2

julia> a[2:4]
3-element Array{Int64,1}:
 2
 3
 4

julia> ra=rand(1:10, 6)
6-element Array{Int64,1}:
  5
  2
  6
 10
  1
  5

julia> b=[1,2,2.5]
3-element Array{Float64,1}:
 1.0
 2.0
 2.5

List Comprehension in Julia

julia> pow2 = Array{Int64}(undef, 10)
10-element Array{Int64,1}:
 4634856432
 4634856352
          1
 4634856512
 4634856592
 4634856672
          8
          4
          2
          1

julia> pow2[1] = 2
2

julia> [pow2[i] = 2^i for i = 2:length(pow2)]; pow2
10-element Array{Int64,1}:
    2
    4
    8
   16
   32
   64
  128
  256
  512
 1024

建立空白沒有任何元素的 array

julia> empty_array = Float64[]
0-element Array{Float64,1}

julia> println(empty_array)
Float64[]

julia> push!(empty_array,1.1)
1-element Array{Float64,1}:
 1.1

julia> push!(empty_array,2.2,3.3)
3-element Array{Float64,1}:
 1.1
 2.2
 3.3

julia> append!(empty_array,[101.1,202.2,303.3])
6-element Array{Float64,1}:
   1.1
   2.2
   3.3
 101.1
 202.2
 303.3

產生 4x1 matrix

julia> X = Array{Int64}(undef, 4,1)
4×1 Array{Int64,2}:
 4371931344
 4367076560
 4496885520
 4405372192

julia> fill!(X,4)
4×1 Array{Int64,2}:
 4
 4
 4
 4

julia> X[2] = 10; X
4×1 Array{Int64,2}:
  4
 10
  4
  4

矩陣

# 產生 3x2 矩陣
julia> A = [2 4; 8 16; 32 64]
3×2 Array{Int64,2}:
  2   4
  8  16
 32  64

# reshape 可轉換為轉置矩陣 2x3
julia> println(reshape(A,2,3))
[2 32 16; 8 4 64]

julia> println(reshape(A,1,6))
[2 8 32 4 16 64]

# transpose 也是轉置矩陣
julia> transpose(A)
2×3 LinearAlgebra.Transpose{Int64,Array{Int64,2}}:
 2   8  32
 4  16  64

矩陣的加法跟乘法

julia> B = [1 1 2; 3 5 8]
2×3 Array{Int64,2}:
 1  1  2
 3  5  8

julia> transpose(A)+B
2×3 Array{Int64,2}:
 3   9  34
 7  21  72

julia> transpose(A)*transpose(B)
2×2 Array{Int64,2}:
  74  302
 148  604

有一種特別的矩陣乘法 .*,就是將各對應元素相乘,而不是標準的矩陣乘法

julia> transpose(A).*B
2×3 Array{Int64,2}:
  2   8   64
 12  80  512

julia> transpose(A) .== B
2×3 BitArray{2}:
 false  false  false
 false  false  false

rand 可產生亂數矩陣

julia> multiA = rand(3,3,3)
3×3×3 Array{Float64,3}:

sparse matrix 稀疏矩陣: 矩陣內大部分的元素都是0

julia> using SparseArrays

julia> sm = spzeros(5,5)
5×5 SparseMatrixCSC{Float64,Int64} with 0 stored entries

julia> sm[1,1] = 10
10

julia> sm
5×5 SparseMatrixCSC{Float64,Int64} with 1 stored entry:
  [1, 1]  =  10.0

Understanding DataFrames

DataFrame 是有 labeled columns 的 data structure,很像是 SQL table/spreadsheet,2 dimensions,可視為 a list of dictionaries

DataFrames.jl 這個 package 處理,建議用在 statistical analysis

在新版 julia 1.0 以後,DataArray 不能使用了 改用 missing 代表 missing value

# 首先必須要先知道 array,可能會有兩種資料型別,要事先定義
julia> x = Union{Missing, String}["a", "b"]
2-element Array{Union{Missing, String},1}:
 "a"
 "b"

# 就可以將某個元素設定為 missing
julia> x[1] = missing
missing

julia> x
2-element Array{Union{Missing, String},1}:
 missing
 "b"

julia> Pkg.add("DataFrames")

julia> using DataFrames

julia> df = DataFrame(Name = ["Julia", "Python"], Version = [0.5, 3.6])
2×2 DataFrame
│ Row │ Name   │ Version │
│     │ String │ Float64 │
├─────┼────────┼─────────┤
│ 1   │ Julia  │ 0.5     │
│ 2   │ Python │ 3.6     │

References

Learning Julia