Julia の基礎知識
●Julia のデータ型
Julia のデータ型は階層構造 (木構造) になっていて、ルートのデータ型が Any になります。型の名前は先頭が英大文字になります。すべての型は Any を継承していると考えてください。
型は抽象型と具象型の二種類があり、実際のデータ (値) に対応するのが具象型で、抽象型は値を生成することはできません。木構造でいえば、「葉」に相当する型が具象型、それ以外の「節」に相当する型が抽象型となります。抽象型を継承して新しい型を作ることはできますが、逆に具象型を継承して新しい型を作ることはできません。
値の型は関数 typeof() や isa() で、上位の型は関数 supertype() で、下位の型 (サブタイプ) は関数 subtypes() で調べることができます。また、Type1 <: Type2 で Type1 が Type2 のサブタイプか調べることもできます。
julia> typeof(12345)
Int64
julia> typeof(1.2345)
Float64
julia> isa(1, Int64)
true
julia> isa(1, Float64)
false
julia> subtypes(Number)
3-element Vector{Any}:
Base.MultiplicativeInverses.MultiplicativeInverse
Complex
Real
|
julia> subtypes(Real)
4-element Vector{Any}:
AbstractFloat
AbstractIrrational
Integer
Rational
julia> supertype(Int64)
Signed
julia> supertype(Signed)
Integer
julia> Int64 <: Number
true
julia> Int64 <: Any
true
|
●基本的なデータ型
- 整数
- Int8, Int16, Int32, Int64, Int128 (数字はビット数)
- UInt8, UInt16, UInt32, UInt64, UInt128 (無符号整数)
- Int (Int32 または Int64, 処理系依存)
- UInt (UInt32 または UInt64, 処理系依存)
- BigInt (多倍長整数)
- 数字の先頭に 0b, 0o, 0x を付けると 2 進数, 8 進数, 16 進数になり、無符号整数として扱われる
- 浮動小数点数
- Float16 (半精度)
- Float32 (単精度)
- Float64 (倍精度)
- BigFloat (任意精度, デフォルトは 256 ビット)
- 複素数, X + Yim
- Complex{T} (実数部 X と虚数部 Y が T 型の数)
- Complex32 (実数部 X と虚数部 Y が Float32)
- Complex64 (実数部 X と虚数部 Y が Float64)
- 有理数 (分数), P // Q
- Rational{T} (分子 P と分母 Q が T 型 の整数)
- 真偽値 Bool (true, false)
- 文字 Char, ' で囲む ('a', 'A' など)
- 文字列 String, " で囲む
- """ で囲むとヒアドキュメント
- \n (改行) や \t (タブ) といったエスケープシーケンスを含めることができる
- 演算子 * で文字列を連結できる
- 変数展開 $var, 変数 var の値に置き換える
- 式展開 $(expr), 式 expr を計算した値に置き換える
- 文字列の前に r を付けると、エスケープシーケンスや変数 (式) 展開が無効になる
- length(str), 文字数を返す
- "" は空文字列
- isempty("") は true を返す
julia> 12345
12345
julia> typeof(12345)
Int64
julia> 1.2345
1.2345
julia> typeof(1.2345)
Float64
julia> 1//2
1//2
|
julia> typeof(1//2)
Rational{Int64}
julia> 1 + 2im
1 + 2im
julia> typeof(1 + 2im)
Complex{Int64}
julia> true
true
julia> typeof(true)
Bool
|
julia> 'a'
'a': ASCII/Unicode U+0061 (category Ll: Letter, lowercase)
julia> typeof('a')
Char
julia> "hello, julia!"
"hello, julia!"
julia> typeof("hello, julia!")
String
julia> "abc" * "def"
"abcdef"
|
julia> "1 + 2 = $(1 + 2)"
"1 + 2 = 3"
julia> r"1 + 2 = $(1 + 2)"
r"1 + 2 = $(1 + 2)"
julia> isempty("")
true
julia> isempty("oops!")
false
|
●基本的な演算子
- 算術演算子 (+, -, *, /, %, div(), \, ^)
- 除算 / の結果は浮動小数点数、div() の結果は整数
- x \ y は y / x, x ^ y は x の y 乗 (べき乗)
- 2 * x や 2 * (x + 1) は 2x や 2(x + 1) のように * を省略できる
- 比較演算子 (==, !=, ===, !==, <, >, <=, >=)
- 比較演算子は a < b < c のようにつなげて使うことができる
- === と !== はオブジェクトのアドレスを比較する (Python の is, Lisp の関数 eq みたいなもの)
- 同じ値のオブジェクトでも === で比較すると false を返す場合がある
- シングルトンオブジェクトであれば必ず true を返す
- 論理演算子 (!, &&, ||)
- ビット演算子 (~, &, |, <<, >>, >>>)
- >>> は論理右シフト, >> は算術右シフト
- 排他的論理和は関数 xor() を使う
- 代入演算子 (=, +=, *=, -=, /=, %=, \=, ^=, &=, |=, <<=, >>=, >>>=)
- Julia の場合、変数の宣言は不要、必要なときに値を代入すればよい
- 変数の型は 名前 :: データ型 で指定する (省略すると Any になる)
- トップレベルで使用される変数は大域変数になる
julia> 1 + 2
3
julia> 1 - 2
-1
julia> 2 * 3
6
julia> 4 / 2
2.0
julia> div(4, 2)
2
julia> 5 / 2
2.5
julia> div(5, 2)
2
julia> 5 \ 2
0.4
julia> 2 ^ 8
256
julia> 1 < 2
true
|
julia> 1 > 2
false
julia> 1 == 2
false
julia> 1 != 2
true
julia> 1 < 2 < 3
true
julia> 1 < 2 > 3
false
julia> !true
false
julia> true && true
true
julia> true && false
false
julia> true || false
true
julia> 0b0101 & 0b0011
0x01
|
julia> 0b0101 | 0b0011
0x07
julia> xor(0b0101, 0b0011)
0x06
julia> 1 << 8
256
julia> 256 >> 8
1
julia> a = 10
10
julia> a += 10
20
julia> a
20
julia> a -= 1
19
julia> a
19
julia> a <<= 1
38
|
julia> a
38
●基本的なデータ構造
- 配列
- データ型は Array{T, n}, T は要素のデータ型, n は次元数
- 汎用のコンストラクタは Array{T, n}(undef , x1, x2, ..., xn)
- 第 1 引数は UndefInitializer 型のオブジェクトを渡す
- undef は UndefInitializer のシングルトンオブジェクト
- 古いバージョン (ver 1.0) の場合、要素は初期化されないが、ver 1.6 ではゼロに初期化される
- xi は各次元の大きさ
- 次元数 n は省略してもよい
- 1 次元配列は [item1, item2, ..., itemN] でも生成できる
- Vector{T} は Array{T, 1} の別名
- [] は空の配列
- 要素の区切りはセミコロン ( ; ) でもよい
- 要素のデータ型は角カッコの前で指定できる, Int128[ ... ] など
- 要素のアクセスは角カッコ [ ] を使う
- 添字は 1 から始まる、末尾の要素は end で指定できる
- 2 次元配列は [x11 x12 x13; x21 x22 x23; x31 x32 x33] のように、要素を空白で、行をセミコロン ( ; ) で区切る
- 添字は [x, y] のようにカンマで区切って指定する
- x in xs で配列 xs の中に x が含まれているか検索できる
- [[x11, x12, x13], [x21, x22, x23], [x31, x32, x33]] は 1 次元配列を格納した 1 次元配列になる
- この場合は 2 つの角カッコ [][] を使って要素にアクセスする
- 主要な関数
- zeros(T, n1, ...), 要素が 0 の配列を生成する, T を省略すると 0.0 (Float64)
- ones(T, n1, ...), 要素が 1 の配列を生成する, T を省略すると 1.0 (Float64)
- falses(n1, ...), 要素が false のビット配列 (BitArray) を生成する
- trues(n1, ...), 要素が true のビット配列を生成する
- length(a), 配列 a の要素数を求める
- sum(a), 配列 a の総和を求める
- isempty(a), 配列 a が空であれば true を返す
- 1 次元配列の操作
- first(a), 配列 a の先頭要素を返す
- last(a), 配列 a の末尾要素を返す
- push!(a, x), 配列 a の末尾に x を追加する
- pop!(a), 配列 a の末尾から要素を取り除いて返す
- pushfirst!(a, x), 配列 a の先頭に x を追加する
- popfirst!(a), 配列 a の先頭から要素を取り除いて返す
- insert!(a, i, x), 配列 a の i 番目に x を挿入する
- Julia の場合、データ構造を破壊的に修正する関数には名前の後ろに ! を付ける習慣がある
- これは Scheme と同じ
julia> a = [1, 2, 3, 4, 5]
5-element Vector{Int64}:
1
2
3
4
5
julia> typeof(a)
Vector{Int64} (alias for Array{Int64, 1})
julia> a[1]
1
julia> a[5]
5
julia> a[1] = 10
10
julia> a
5-element Vector{Int64}:
10
2
3
4
5
julia> []
Any[]
julia> Int[]
Int64[]
julia> isempty([1, 2, 3])
false
julia> isempty(Int[])
true
julia> b = [1 2 3; 4 5 6; 7 8 9]
3×3 Array{Int64,2}:
1 2 3
4 5 6
7 8 9
julia> b[1, 1]
1
julia> b[2, 1]
4
julia> b[3, 3]
9
julia> b[2, 2] *= 10
50
julia> b
3×3 Array{Int64,2}:
1 2 3
4 50 6
7 8 9
julia> 1 in b
true
julia> 10 in b
false
julia> c = [[1, 2], [3, 4, 5], [6, 7, 8, 9]]
3-element Vector{Vector{Int64}}:
[1, 2]
[3, 4, 5]
[6, 7, 8, 9]
julia> c[1][1]
1
julia> c[3][4]
9
- タプル
- データ型は Tuple{T, U, V, ...}, T, U, V, ... は要素のデータ型
- タプルは immutable なデータ構造
- タプルは丸カッコ (item1, item2, ...) で生成する (丸カッコは省略可)
- () は空のタプル
- isempty(tup), tup が空ならば true を返す
- length(tup), 要素数を返す
- 要素のアクセスは角カッコ [ ] を使う
- 変数の多重代入や関数で多値を返すときにも使える
julia> ()
()
julia> typeof(())
Tuple{}
julia> isempty(())
true
julia> isempty((1, 2, 3))
false
julia> (1,)
(1,)
julia> typeof((1,))
Tuple{Int64}
julia> a = (1, 2, 3)
(1, 2, 3)
julia> a[1]
1
julia> a[2]
2
- 辞書
- データ型は Dict{K, V}, K はキーのデータ型、V は値のデータ型
- 辞書は Dict{K, V}(k1=>v1, k2=>v2, ...) で生成する (型指定は省略可)
- key => val は Pair(key, val) を生成する
- Dict{K, V}() は空の辞書を生成する
- 要素のアクセスは角カッコ [ ] を使う
- キーの有無は haskey(dic, key) で判定する
- delete!(dic, key), 辞書 dic からキー key とその値を削除する
- keys(dic), KeySet (キーを格納した集合) を返す
- values(dic), 値のイテレータ (ValueIterator) を返す
- isempty(dic), dic が空であれば true を返す
- length(dic), 要素数を返す
julia> d = Dict("foo"=>100, "bar"=>200, "baz"=>300)
Dict{String,Int64} with 3 entries:
"bar" => 200
"baz" => 300
"foo" => 100
julia> typeof(d)
Dict{String,Int64}
julia> d["foo"]
100
julia> d["foo"] = 1000
1000
julia> d
Dict{String,Int64} with 3 entries:
"bar" => 200
"baz" => 300
"foo" => 1000
julia> d["oops"] = 2000
2000
julia> d
Dict{String,Int64} with 4 entries:
"bar" => 200
"baz" => 300
"oops" => 2000
"foo" => 1000
julia> haskey(d, "foo")
true
julia> haskey(d, "Foo")
false
julia> keys(d)
KeySet for a Dict{String,Int64} with 4 entries. Keys:
"bar"
"baz"
"oops"
"foo"
julia> values(d)
ValueIterator for a Dict{String,Int64} with 4 entries. Values:
200
300
2000
1000
julia> isempty(d)
false
julia> for k = keys(d)
delete!(d, k)
end
julia> isempty(d)
true
- 集合
- データ型は Set{T}, T は要素のデータ型
- Set{T}([item1, item2, ..., itemN]) で生成する, {T} は省略可
- Set{T}() は空の集合を生成する
- isempty(set), set が空であれば true を返す
- length(set), 要素数を返す
- x in xs で集合 xs に x があるかチェックできる
- 和集合 union(), 積集合 intersect(), 差集合 setdiff()
julia> a = Set([1, 2, 3, 4])
Set{Int64} with 4 elements:
4
2
3
1
julia> typeof(a)
Set{Int64}
julia> 1 in a
true
julia> 10 in a
false
julia> isempty(a)
false
julia> length(a)
4
julia> isempty(Set())
true
julia> length(Set())
0
julia> b = Set([3, 4, 5, 6])
Set{Int64} with 4 elements:
5
4
6
3
julia> union(a, b)
Set{Int64} with 6 elements:
5
4
6
2
3
1
julia> intersect(a, b)
Set{Int64} with 2 elements:
4
3
julia> setdiff(a, b)
Set{Int64} with 2 elements:
2
1
julia> setdiff(b, a)
Set{Int64} with 2 elements:
5
6
●範囲オブジェクト (range object)
- start : stop で start から 1 刻みで stop までの列を表す
- start : step : stop で start から step 刻みで stop までの列を表す
- 配列に格納する場合は collect() を使う, collect(1:3) => [1, 2, 3]
- 配列の部分列を指定するときにも使える
julia> 1 : 10
1:10
julia> typeof(1 : 10)
UnitRange{Int64}
julia> 1 : 2 : 10
1:2:9
julia> typeof(1 : 2 : 10)
StepRange{Int64,Int64}
julia> collect(1:5)
5-element Vector{Int64}:
1
2
3
4
5
julia> collect(1:2:5)
3-element Vector{Int64}:
1
3
5
●制御構造
- コメントは # から改行まで
- #= と =# に囲まれた範囲もコメントになる (入れ子にしてもよい)
- if test1 ... elseif test2 ... else ... end
- 三項演算子 ?, :
- while test ... end
- for 変数 = range_or_collection ... end
- = のかわりに in や ∈ を使用できる
- for (変数, ...) = collection ... end (変数を複数定義するときはカッコが必要)
- for var1 = range_or_collection1, ..., varN = range_or_collectionN ... end で N 重のループになる
- 繰り返しの制御に break と continue が使える
- begin ... end または (...; ...; ...), 最後に評価した式の値を返す
- 1 行に書くときは式をセミコロン ( ; ) で区切る
- 内包表記
- [x * x for x = [1, 2, 3]] => [2, 6, 9]
- [x for x = 1 : 10 if x % 2 == 0] =>: [2, 4, 6, 8, 10]
julia> if true 1 else 0 end
1
julia> if false 1 else 0 end
0
julia> a = true ? 1 : 0
1
julia> a
1
julia> a = false ? 1 : 0
0
julia> a
0
julia> for i = 1:10 println("hello, Julia") end
hello, Julia
hello, Julia
hello, Julia
hello, Julia
hello, Julia
hello, Julia
hello, Julia
hello, Julia
hello, Julia
hello, Julia
julia> for i = 1:3, j = 4:6 println("$i, $j") end
1, 4
1, 5
1, 6
2, 4
2, 5
2, 6
3, 4
3, 5
3, 6
julia> i = 0
0
julia> while i < 10
println("hello, Julia")
global i += 1 # global 宣言は「変数」を参照
end
hello, Julia
hello, Julia
hello, Julia
hello, Julia
hello, Julia
hello, Julia
hello, Julia
hello, Julia
hello, Julia
hello, Julia
julia> [x * x for x = 1:5]
5-element Vector{Int64}:
1
4
9
16
25
julia> [x for x = 1:10 if x % 2 == 0]
5-element Vector{Int64}:
2
4
6
8
10
- print() でデータを表示、println() は改行する
●関数
- 関数のデータ型は Function
- 関数定義は function 関数名(仮引数::データ型, ...) ... end
- 関数名(仮引数::データ型, ...) = 式 でも定義できる
- 局所関数も定義できる
- 引数のデータ型は省略可 (Any になる)
- 関数は最後に評価した式の値を返す (return で返すこともできる)
- 関数呼び出しは 関数名(実引数, ...)
- foo(引数, ..., 引数 = 値, ...) オプショナル引数
- foo(引数, ...; 名前 = 値, ...) セミコロン以降はキーワード引数
- foo(引数, ..., 引数...) 引数... は可変長引数 (タプルに格納されて引数にセット)
- タプル tup や配列の要素を関数 foo() の引数に渡すときは foo(tup...) とする
- Julia の関数は first class object
- 高階関数は map, filter, reduce など多数用意されている
- func(...) do 引数 ... end, do block (Ruby のブロックと同じ)
- 無名関数は function(仮引数, ...) ... end または (仮引数, ...) -> 式
- もちろんクロージャもサポートされている
- 末尾再帰最適化はサポートされていない
- julia の関数は総称関数 (generic function) で、引数の個数が異なるか引数のデータ型が異なれば多重定義できる
- 呼び出される関数は引数の個数および個々のデータ型により選択される (多重ディスパッチ)
julia> foo(x) = x^2
foo (generic function with 1 method)
julia> foo(x, y) = x^2 + y^2
foo (generic function with 2 methods)
julia> foo(x, y, z) = x^2 + y^2 + z^2
foo (generic function with 3 methods)
julia> foo(3)
9
julia> foo(3, 4)
25
julia> foo(3, 4, 5)
50
julia> bar(x::Int) = println("bar:Int")
bar (generic function with 1 method)
julia> bar(x::Float64) = println("bar:Float64")
bar (generic function with 2 methods)
julia> bar(1)
bar:Int
julia> bar(1.2345)
bar:Float64
julia> baz(x::Int, y::Int) = println("baz, Int, Int")
baz (generic function with 1 method)
julia> baz(x::Int, y::Float64) = println("baz, Int, Float")
baz (generic function with 2 methods)
julia> baz(x::Float64, y::Float64) = println("baz, Float, Float")
baz (generic function with 3 methods)]
julia> baz(1, 2)
baz, Int, Int
julia> baz(1, 0.1)
baz, Int, Float
julia> baz(1.1, 1.2)
baz, Float, Float
julia> baz(1.1, 2)
ERROR: MethodError: no method matching baz(::Float64, ::Int64)
Closest candidates are:
baz(::Float64, ::Float64) at REPL[186]:1
baz(::Int64, ::Int64) at REPL[184]:1
julia> map(x -> x * x, [1, 2, 3, 4, 5])
5-element Vector{Int64}:
1
4
9
16
25
julia> map([1, 2, 3, 4, 5]) do x x * x end
5-element Vector{Int64}:
1
4
9
16
25
julia> function adder(n) x -> n + x end
adder (generic function with 1 method)
julia> add10 = adder(10)
#23 (generic function with 1 method)
julia> add10(100)
110
julia> add100 = adder(100)
#23 (generic function with 1 method)
julia> add100(100)
200
●変数と有効範囲
- 変数の宣言は不要、必要なときに値を代入すればよい
- 関数の引数や関数の中で値を代入した変数は「局所変数 (local variable)」になる
- 関数の引数やその中の局所変数の有効範囲 (スコープ, scope) は関数の終わり (end) まで
- 変数の型は 名前 :: データ型 で指定する (省略可 Any になる)
- トップレベルで値を代入された変数は「大域変数 (global variable)」になる
- 変数を参照するときは局所変数から探索する
- 見つからない場合は大域変数を参照する (それでも見つからない場合はエラー)
リスト : 大域変数と局所変数 (test01.jl)
function foo(n)
x = 0 # n, x は局所変数
while x < n
x += 1
println(x)
end
println(x)
println(y) # y は大域変数を参照する
# println(z) z は定義されていないのでエラーになる
end
x = 100 # x, y は大域変数
y = 200
foo(5)
$ julia test01.jl
1
2
3
4
5
5
200
- for で宣言した変数は新しい局所変数になる
- 同名の局所変数は隠蔽される
- このときの局所変数の有効範囲は for の終わり (end) まで
- このあと説明する let ... end と同じ
- for や while ループの中だけで使用される局所変数の有効範囲もループの終わりまでになる
リスト : for 文と変数の有効範囲 (test02.jl)
function foo(n)
x = 0 # x は局所変数 (x_1 とする)
for x = 0 : n - 1 # 新しい局所変数 x (x_2 とする)
x += 1
println(x)
z = x * 2 # 新しい局所変数 z
println(z)
end # x_2 と z の有効範囲はここまで
println(x) # x_1 を参照する
println(y) # y は大域変数を参照する
# println(z) z は定義されていないのでエラーになる
end
x = 100 # x, y は大域変数
y = 200
foo(5)
$ julia test02.jl
1
2
2
4
3
6
4
8
5
10
0
200
- 局所変数は local で、大域変数は global で宣言できる
- 関数やループの中で大域変数を書き換えたい場合は global 宣言が必要になる
- for 文の変数で、外側の局所変数を使用したい場合は outer を付ける
julia> x = 0
0
julia> while x < 5; println("hello, world"); global x += 1 end
hello, world
hello, world
hello, world
hello, world
hello, world
julia> x
5
julia> (local x; for outer x = 1:10 println(x) end; println(x))
1
2
3
4
5
6
7
8
9
10
10
julia> x
5
- 局所変数は let ... end でも定義できる
- このときの局所変数の有効範囲は end まで
julia> x, y = 1, 2 # 大域変数
(1, 2)
julia> let x = 10, y = 20 # (A)
let x = 100, y = 200 # (B)
println(x, y) # (B) の x, y を表示
end # (B) で定義した変数の有効範囲はここまで
println(x, y) # (A) の x, y を表示
end # (A) で定義した変数の有効範囲はここまで
100200
1020
julia> println(x ,y) # 大域変数を表示
12
簡単なプログラム
●FizzBuzz
リスト : FizzBuzz 問題
function fizzbuzz()
for x = 1 : 100
if x % 15 == 0
print("FizzBuzz")
elseif x % 3 == 0
print("Fizz")
elseif x % 5 == 0
print("Buzz")
else
print(x)
end
print(" ")
end
end
fizzbuzz()
$ julia fizzbuzz.jl
1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz 16 17 Fizz 19 Buzz Fizz
22 23 Fizz Buzz 26 Fizz 28 29 FizzBuzz 31 32 Fizz 34 Buzz Fizz 37 38 Fizz Buzz
41 Fizz 43 44 FizzBuzz 46 47 Fizz 49 Buzz Fizz 52 53 Fizz Buzz 56 Fizz 58 59
FizzBuzz 61 62 Fizz 64 Buzz Fizz 67 68 Fizz Buzz 71 Fizz 73 74 FizzBuzz 76 77
Fizz 79 Buzz Fizz 82 83 Fizz Buzz 86 Fizz 88 89 FizzBuzz 91 92 Fizz 94 Buzz Fizz
97 98 Fizz Buzz
●数値積分
リスト : 中点則で円周率を求める
function midpoint(n)
w = 1.0 / n
s = 0.0
for i = 1 : n
x = (i - 0.5) * w;
s += 4.0 / (1.0 + x * x);
end
s * w
end
print(midpoint(10000))
- 0 - 9 の数字は整数 (Int32 または Int64) に、小数点数は指数付きの数字は浮動小数点数 (Float64) になる
- 他のデータ型に変換するには データ型(値) とする (BigInt(123) など)
$ julia midpoint.jl
3.141592654423134
●平均値と標準偏差
リスト : 平均値と標準偏差
# 乱数で生成した身長のデータ
# データ型は Vector{Float64} になる
height = [
148.7, 149.5, 133.7, 157.9, 154.2, 147.8, 154.6, 159.1, 148.2, 153.1,
138.2, 138.7, 143.5, 153.2, 150.2, 157.3, 145.1, 157.2, 152.3, 148.3,
152.0, 146.0, 151.5, 139.4, 158.8, 147.6, 144.0, 145.8, 155.4, 155.5,
153.6, 138.5, 147.1, 149.6, 160.9, 148.9, 157.5, 155.1, 138.9, 153.0,
153.9, 150.9, 144.4, 160.3, 153.4, 163.0, 150.9, 153.3, 146.6, 153.3,
152.3, 153.3, 142.8, 149.0, 149.4, 156.5, 141.7, 146.2, 151.0, 156.5,
150.8, 141.0, 149.0, 163.2, 144.1, 147.1, 167.9, 155.3, 142.9, 148.7,
164.8, 154.1, 150.4, 154.2, 161.4, 155.0, 146.8, 154.2, 152.7, 149.7,
151.5, 154.5, 156.8, 150.3, 143.2, 149.5, 145.6, 140.4, 136.5, 146.9,
158.9, 144.4, 148.1, 155.5, 152.4, 153.3, 142.3, 155.3, 153.1, 152.3,
]
# 平均値と標準偏差
function meansd(xs)
m = sum(xs) / length(xs)
s = 0.0
for x = xs
s += (x - m) * (x - m)
end
m, sqrt(s / length(xs))
end
# 1 回の読み込みで求める
function meansd2(xs)
m, s = 0.0, 0.0
k = length(xs)
for i = 1 : k
x = xs[i] - m
m += x / i
s += (i - 1) * x * x / i
end
m, sqrt(s / k)
end
println(meansd(height))
println(meansd2(height))
$ julia mean.jl
(150.62699999999998, 6.433472701426501)
(150.62699999999998, 6.433472701426506)
●パスカルの三角形
リスト : パスカルの三角形
# 2 次元配列版
function pascal(n)
table = ones(Int, n, n)
for i = 3 : n, j = 2 : i - 1
table[i, j] = table[i - 1, j - 1] + table[i - 1, j]
end
for i = 1 : n
for j = 1 : i
print(table[i, j], " ")
end
println("")
end
end
# 1 次元配列版
function pascal1(n)
table = ones(Int, n)
println(table[1])
println(table[1], " ", table[2])
for i = 3 : n
for j = i - 1 : -1 : 2
table[j] += table[j - 1]
end
# 表示
for j = 1 : i
print(table[j], " ")
end
println("")
end
end
pascal(15)
# pascal1(15)
$ julia pascal.jl
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
1 7 21 35 35 21 7 1
1 8 28 56 70 56 28 8 1
1 9 36 84 126 126 84 36 9 1
1 10 45 120 210 252 210 120 45 10 1
1 11 55 165 330 462 462 330 165 55 11 1
1 12 66 220 495 792 924 792 495 220 66 12 1
1 13 78 286 715 1287 1716 1716 1287 715 286 78 13 1
1 14 91 364 1001 2002 3003 3432 3003 2002 1001 364 91 14 1
●素数
リスト : 素数
# 単純版
function checkPrime(ps, x)
for p = ps
if p * p > x; break; end
if x % p == 0; return false; end
end
true
end
function makePrimes(n)
ps = [2]
x = 1
for x = 3 : 2 : n
if checkPrime(ps, x); push!(ps, x); end
end
ps
end
# エラトステネスの篩 (1)
function sieve(n)
ps = [2]
xs = collect(3 : 2 : n)
while xs[1] * xs[1] <= n
p = xs[1]
push!(ps, p)
filter!(x -> x % p != 0, xs)
end
append!(ps, xs)
end
# エラトステネスの篩 (2)
function sieve1(n)
ps = [2]
k = div(n, 2)
xs = trues(k)
x = 3
while x * x <= n
i = div(x, 2)
if xs[i]
push!(ps, x)
for j = i + x : x : k; xs[j] = false; end
end
x += 2
end
while x <= n
i = div(x, 2)
if xs[i]; push!(ps, x); end
x += 2
end
ps
end
println(makePrimes(1000))
# println(sieve(1000))
# println(sieve1(1000))
- 1 行に複数の処理を記述するときはセミコロン (;) で区切る
- filter!(func, xs) は関数 func が偽を返す要素を取り除く (xs を破壊的に修正する)
$ julia prime.jl
[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,
107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,
223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,
337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,
457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,
593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,
719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,
857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,
997]
●素因数分解
リスト : 素因数分解 (試し割り)
function factorSub(n, m)
c = zero(n)
while n % m == 0
c += 1
n = div(n, m)
end
c, n
end
function factorization(n)
x::typeof(n) = 2
xs = Pair{typeof(n), typeof(n)}[]
c, m = factorSub(n, x)
if c > 0
push!(xs, x => c)
end
x = 3
while x * x <= m
c, m = factorSub(m, x)
if c > 0
push!(xs, x => c)
end
x += 2
end
if m > 1
push!(xs, m => one(n))
end
xs
end
println(factorization(24))
println(factorization(12345678))
println(factorization(123456789))
println(factorization(1234567890))
println(factorization(1111111111))
for x = 2 : 31
println(factorization(2 ^ x - 1))
end
- typeof() の結果はデータ型の指定にも使える
$ julia factor.jl
[2 => 3, 3 => 1]
[2 => 1, 3 => 2, 47 => 1, 14593 => 1]
[3 => 2, 3607 => 1, 3803 => 1]
[2 => 1, 3 => 2, 5 => 1, 3607 => 1, 3803 => 1]
[11 => 1, 41 => 1, 271 => 1, 9091 => 1]
[3 => 1]
[7 => 1]
[3 => 1, 5 => 1]
[31 => 1]
[3 => 2, 7 => 1]
[127 => 1]
[3 => 1, 5 => 1, 17 => 1]
[7 => 1, 73 => 1]
[3 => 1, 11 => 1, 31 => 1]
[23 => 1, 89 => 1]
[3 => 2, 5 => 1, 7 => 1, 13 => 1]
[8191 => 1]
[3 => 1, 43 => 1, 127 => 1]
[7 => 1, 31 => 1, 151 => 1]
[3 => 1, 5 => 1, 17 => 1, 257 => 1]
[131071 => 1]
[3 => 3, 7 => 1, 19 => 1, 73 => 1]
[524287 => 1]
[3 => 1, 5 => 2, 11 => 1, 31 => 1, 41 => 1]
[7 => 2, 127 => 1, 337 => 1]
[3 => 1, 23 => 1, 89 => 1, 683 => 1]
[47 => 1, 178481 => 1]
[3 => 2, 5 => 1, 7 => 1, 13 => 1, 17 => 1, 241 => 1]
[31 => 1, 601 => 1, 1801 => 1]
[3 => 1, 2731 => 1, 8191 => 1]
[7 => 1, 73 => 1, 262657 => 1]
[3 => 1, 5 => 1, 29 => 1, 43 => 1, 113 => 1, 127 => 1]
[233 => 1, 1103 => 1, 2089 => 1]
[3 => 2, 7 => 1, 11 => 1, 31 => 1, 151 => 1, 331 => 1]
[2147483647 => 1]
●再帰定義
リスト : 再帰定義
# 階乗
function fact(n)
if n == 0
BigInt(1) # one(n) とすると引数 n のデータ型で値を求める
else
n * fact(n - 1)
end
end
# 階乗 (繰り返し版)
function facti(n)
a = BigInt(1) # a::BigInt = 1 でもよい
for x = 2 : n
a *= x
end
a
end
# フィボナッチ数 (二重再帰)
function fibo(n)
if n == 0
0
elseif n == 1
1
else
fibo(n - 2) + fibo(n - 1)
end
end
# フィボナッチ数 (繰り返し版)
function fiboi(n)
a = BigInt(0) # zero(n)
b = BigInt(1) # one(n) とすると引数のデータ型で値を求める
for _ = 1 : n
a, b = b, a + b
end
a
end
for x = 0:20
println(fact(x))
end
println(facti(50))
for x = 0:20
print(fibo(x), " ")
end
println("")
println(fiboi(50))
println(fiboi(100))
- BigInt() や BigFloat() のかわりに関数 big() が使える
- Julia には階乗を求める関数 factorial() がある
- factorial() でオーバーフローするときは引数を big() で変換する
- zero(x) は引数 x のデータ型の 0 を返す
- one(x) は引数 x のデータ型の 1 を返す
$ julia fact.jl
1
1
2
6
24
120
720
5040
40320
362880
3628800
39916800
479001600
6227020800
87178291200
1307674368000
20922789888000
355687428096000
6402373705728000
121645100408832000
2432902008176640000
30414093201713378043612608166064768844377641568960512000000000000
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765
12586269025
354224848179261915075
●高階関数
リスト : 高階関数
# マッピング
function map1(fn, xs)
a::typeof(xs) = []
for x = xs
push!(a, fn(x))
end
a
end
# フィルター
function filter1(fn, xs)
a::typeof(xs) = []
for x = xs
if fn(x)
push!(a, x)
end
end
a
end
# 畳み込み
function foldleft(fn, a, xs)
for x = xs
a = fn(a, x)
end
a
end
xs = collect(1:10)
println(map1(x -> x * x, xs))
println(map(x -> x * x, xs))
println(filter1(x -> x % 2 == 0, xs))
println(filter(x -> x % 2 == 0, xs))
println(foldleft(+, 0, xs))
println(reduce(+, xs, init=0))
- 配列 a のデータ型を指定しないと Array{Any, 1} になる
- Any でもよければデータ型の指定は不要 (どんなデータでも格納できる)
- マッピングは内包表記のほうが簡単 [fn(x) for x = xs]
- map() と filter() には引数 xs を破壊的に修正する map!() と filter!() がある
- reduce() は初期値 (init) を省略すると先頭要素が初期値となる
$ julia higher.jl
[1,4,9,16,25,36,49,64,81,100]
[1,4,9,16,25,36,49,64,81,100]
[2,4,6,8,10]
[2,4,6,8,10]
55
55
julia> reduce((x, y) -> (x, y), [1,2,3])
((1, 2), 3)
julia> reduce((x, y) -> (x, y), [1,2,3], init=0)
(((0, 1), 2), 3)
●組み合わせの数
リスト : 組み合わせの数
# 二重再帰 (とても遅い)
function combination_number(n, r)
if r == 0 || n == r
BigInt(1)
else
combination_number(n - 1, r) + combination_number(n - 1, r - 1)
end
end
# 末尾再帰
function combination_number1(n, r)
if n == 0 || r == 0
BigInt(1)
else
div(combination_number1(n, r - 1) * (n - r + 1), r)
end
end
println(combination_number(22, 11))
println(combination_number1(26, 13))
println(combination_number1(50, 25))
$ julia comb.jl
705432
10400600
126410606437752
●順列と組み合わせ
リスト : 順列と組み合わせ
# xs の中から n 個を選ぶ順列
function permutation(fn, n, xs)
ys::typeof(xs) = []
function perm()
if length(ys) == n
fn(ys)
else
for x = xs
if x in ys; continue; end
push!(ys, x)
perm()
pop!(ys)
end
end
end
perm()
end
# xs の中から n 個を選ぶ組み合わせ
function combination(fn, n, xs)
ys::typeof(xs) = []
function comb(m)
if length(ys) == n
fn(ys)
elseif m <= length(xs)
push!(ys, xs[m])
comb(m + 1)
pop!(ys)
comb(m + 1)
end
end
comb(1)
end
permutation(print, 4, [1, 2, 3, 4])
println("")
combination(print, 3, [1, 2, 3, 4, 5])
println("")
$ julia perm.jl
[1, 2, 3, 4][1, 2, 4, 3][1, 3, 2, 4][1, 3, 4, 2][1, 4, 2, 3][1, 4, 3, 2][2, 1, 3, 4]
[2, 1, 4, 3][2, 3, 1, 4][2, 3, 4, 1][2, 4, 1, 3][2, 4, 3, 1][3, 1, 2, 4][3, 1, 4, 2]
[3, 2, 1, 4][3, 2, 4, 1][3, 4, 1, 2][3, 4, 2, 1][4, 1, 2, 3][4, 1, 3, 2][4, 2, 1, 3]
[4, 2, 3, 1][4, 3, 1, 2][4, 3, 2, 1]
[1, 2, 3][1, 2, 4][1, 2, 5][1, 3, 4][1, 3, 5][1, 4, 5][2, 3, 4][2, 3, 5]
[2, 4, 5][3, 4, 5]