0. はじめに
本稿では Julia の型を概説します.
Julia では型は Core.typeof()
で,要素の型は Base.eltype()
で見ることができます.
@show typeof("1"), typeof(1)
# (typeof("1"), typeof(1)) = (String, Int64)
@show eltype(["1", "one", "Eins", "un", "ひ", "一"])
# String
型の包含関係は <:
です.
help?> <:
search: <:
<:(T1, T2)
Subtype operator: returns true if and only if all values of type T1 are also
of type T2.
Examples
≡≡≡≡≡≡≡≡≡≡
julia> Float64 <: AbstractFloat
true
julia> Vector{Int} <: AbstractArray
true
julia> Matrix{Float64} <: Matrix{AbstractFloat}
false
1. 整数型 Integer
help?> Integer
search: Integer isinteger
Integer <: Real
Abstract supertype for all integers.
1.1 Int64
数値計算する上でまず覚えるとよい型は 64ビット符号付き整数型 Int64
です.
Int
はそのエイリアスです.
全部で Int8 Int64 Int32 Int16 Int128
というビット数の異なる符号付き整数型があります.
Int64 <: Signed <: Integer# true
Int == Int64# true
Int8 <: Int64# false
typemax(Int64) == 2^63 - 1# true
→ Integers and Floating-Point Numbers · The Julia Language
1.2 BigInt
BigInt 型は桁数の制限がほとんどないので大きな整数の計算に使えます.
#%% BigInt
BigInt <: Signed <: Integer# true
Int64 <: BigInt# false
# ERROR: MethodError: no method matching typemax(::Type{BigInt})
# typemax(BigInt)
2^63# -9223372036854775808
big(2)^63# 9223372036854775808
googol = big(10)^100# 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Exponent やメモリのオーバーフローには気をつけましょう.
try
googolplex = big(10)^googol
catch y
if isa(y, OverflowError)
@error "To think googolplex might be absurd!"
end
end
println("Googolplex is not Googleplex.")
┌ Error: To think googolplex might be absurd!
└ @ Main ~/..
Googolplex is not Googleplex.
1.3 ブール型 Bool
Bool 型はプログラミング一般において最も重要な概念のひとつです.
Julia では true
or false
の2値です.
help?> Bool
search: Bool BoundsError
Bool <: Integer
Boolean type, containing the values true and false.
Bool is a kind of number: false is numerically equal to 0 and true is
numerically equal to 1. Moreover, false acts as a multiplicative "strong
zero":
julia> false == 0
true
julia> true == 1
true
julia> 0 * NaN
NaN
julia> false * NaN
0.0
See also: digits, iszero, NaN.
2元 Boole 束の演算を計算することができる他,整数としての計算もできます.
==
が返す値のタイプも Bool
ですので極論これが分かっていないとコーディングできません.
Bool <: Integer# true
typeof(true)# Bool
true & false# false
true | false# true
true + false# 1
typeof(true + 0)# Int64
################
if 1 == 1 && 0 == 1
println("Zero equals one.")
else
@show 0 == 1
end
# 0 == 1 = false
2. 浮動小数点数型 AbstractFloat
Float64 <: AbstractFloat
64-bit floating point number type (IEEE 754 standard).
Binary format: 1 sign, 11 exponent, 52 fraction bits.
2.1 Float64
Julia で倍精度浮動小数点数を表す型は Float64
です.
浮動小数点数型 には Float64 Float32 Float16
があります.
float
で浮動小数点数型に変換できます.
詳しくは help?> float
(REPL で ?
) にあります.
0.0
の表記などほかは C/C++ に似ています.
float(1)# 1.0
typeof(float(1))# Float64
typeof(1 / 2)# Float64
typeof(0.0)# Float64
typeof(1 + 0.0)# Float64
floatmax()# 1.7976931348623157e308
いわゆる最大値は typemax
ではなく floatmax
で出力します.
help?> floatmax
search: floatmax floatmin
floatmax(T = Float64)
Return the largest finite number representable by the floating-point type T.
See also: typemax, floatmin, eps.
Examples
≡≡≡≡≡≡≡≡≡≡
julia> floatmax(Float16)
Float16(6.55e4)
julia> floatmax(Float32)
3.4028235f38
julia> floatmax()
1.7976931348623157e308
julia> typemax(Float64)
Inf
2.2 BigFloat
Bigfloat を使うと桁数が増えます.
BigFloat(pi)# 3.141592653589793238462643383279502884197169399375105820974944592307816406286198
BigFloat(1.0)# 1.0
BigFloat(1.25)# 1.25
BigFloat(1.1)# 1.100000000000000088817841970012523233890533447265625
BigFloat("1.1")# 1.100000000000000000000000000000000000000000000000000000000000000000000000000003
3. 有理数型 Rational
有理数型 Rational
は主に浮動小数点数型にせずに分数計算したいときに用いられ,数値計算では非常に重要な意味を持っています.
Python とくに Sympy で計算したことがある人は任意精度計算(および有理数計算)の意義はおわかりのことと思います.
除算 //
を使います.
div()
と /
は有理数体の演算ではありません.
div()
は整数の除算で /
は浮動小数点演算として解釈されます.
typeof(1 // 2)# Rational{Int64}
typeof(1 // (big(5)^31 * 31))# Rational{BigInt}
div(1,2), typeof(div(1,2))# (0, Int64)
div(-3,2)# -1
typeof(1 / 2)# Float64
help?> div
search: div divrem DivideError splitdrive code_native @code_native
div(x, y)
÷(x, y)
The quotient from Euclidean (integer) division. Generally equivalent to a
mathematical operation x/y without a fractional part.
...
help?> /
search: / //
/(x, y)
Right division operator: multiplication of x by the inverse of y on the
right. Gives floating-point results for integer arguments.
...
4. 複素数型 Complex
Julia では虚数単位 $i$ は im
です.1
typeof(im)# Complex{Bool}
typeof(1im)# Complex{Int64}
typeof(1.0im)# ComplexF64 (alias for Complex{Float64})
complex(1)# 1 + 0im
complex(1,1)# 1 + 1im
(1 + 1im)^2#0 + 2im
Complex
型は Real
から構成されるという観点が取られており かつ Real
型は包含していません.
Real <: Complex# false
help?> Complex
search: Complex complex ComplexF64 ComplexF32 ComplexF16 precompile
Complex{T<:Real} <: Number
Complex number type with real and imaginary part of type T.
ComplexF16, ComplexF32 and ComplexF64 are aliases for Complex{Float16},
Complex{Float32} and Complex{Float64} respectively.
See also: Real, complex, real.
5. 文字列型 String
String
型の「空(くう)文字」は string()
で与えることができます.
文字列への変換も string()
です.
文字列の結合は *
です.+
では行えません.
string()# ""
string(1)# "1"
"Albert" * " Einstein"# "Albert Einstein"
# ERROR: MethodError: no method matching +(::String, ::String)
# "Albert" + " Einstein"
- 文字列は添字を取れます.
"Bill Evans"[end]
# 's': ASCII/Unicode U+0073 (category Ll: Letter, lowercase)
- 繰り返しは
repeat()
か^
です.
repeat("So what? ", 4)
"So what? " ^ 4
# "So what? So what? So what? So what? "
- 応用してみましょう.
DRA = "Don't run away"
line1 = DRA * " now... "
line2 = (DRA * ", ")^3 * DRA * "!"
line1 * line2
# "Don't run away now... Don't run away, Don't run away, Don't run away, Don't run away!"
- 文字列は for 文の宣言で使えます.
for Rhapsody in "Blue"
print(Rhapsody)
if Rhapsody == "Blue"[end]
break
end
print("✰")
end
# B✰l✰u✰e
- プロットなどで $\LaTeX$ 式の数式が出したければ
LaTeXStrings
パッケージを宣言して文字列の前にL
と書きます.
using LaTeXStrings
L"x \\mathrm{[m]}"# L"$x \\mathrm{[m]}$"
6. 集合型 Set
空集合は以下で書きます.小文字の s
では書けません.
Set([])# Set{Any}()
要素の追加は push!()
です.2
!
は破壊的変更の印です.
begin
∅ = Set{Int64}([])
@show isempty(∅)
push!(∅, 1)
@show ∅
end
出力:
isempty(∅) = true
∅ = Set([1])
Set{Int64} with 1 element:
1
- 合併は
union()
です.
println(union(Set([1,2,3]), Set([3,4,5])))
# Set([5, 4, 2, 3, 1])
7. Array 型
Set と異なり Array は順序が全て決まっています.
空列は以下です.
[]# Any[]
Any[]# Any[]
7.1 ベクトル型 Vector
Julia では Vector
は Array{T,1}
のエイリアスです.
数学的にはベクトルの成分表示に対応しています.
Julia の Vector
はそれに加えて Python の list
や np.array
のようにも使います.
help?> Vector
search: Vector BitVector DenseVector StridedVector AbstractVector
Vector{T} <: AbstractVector{T}
One-dimensional dense array with elements of type T, often used to represent
a mathematical vector. Alias for Array{T,1}.
- 空のベクトルは以下のように指定します.
Vector{Float64}()# Float64[]
Float64[]# Float64[]
型指定(型注釈)では ::Vector{Float64}
などと書きます.
julia> typeof(Vector{Float64}())
Vector{Float64} (alias for Array{Float64, 1})
- 要素の型の変換が行えます.
[1,2,3]
#=
3-element Vector{Int64}:
1
2
3
=#
v = Vector{Float64}([1,2,3])
#=
3-element Vector{Float64}:
1.0
2.0
3.0
=#
- 要素の追加は
push!()
で行います.
println(push!(Vector{Float64}([1,2,3]), 4.1))
# [1.0, 2.0, 3.0, 4.1]
-
append!()
は要素の追加ではなく配列の結合です.
println(append!([1,2,3], [3,4,5]))
# [1, 2, 3, 3, 4, 5]
他の関数については Collections and Data Structures · The Julia Language をご覧下さい.
7.2 行列型 Matrix
Julia では Matrix
は Array{T,2}
のエイリアスです.
行列は数学的には2次元的な数列なのでこれは正しいです.3
help?> Matrix
search: Matrix BitMatrix DenseMatrix StridedMatrix AbstractMatrix
Matrix{T} <: AbstractMatrix{T}
Two-dimensional dense array with elements of type T, often used to represent
a mathematical matrix. Alias for Array{T,2}.
計算の具体例です.
A = [1 2; 3 4im]
2×2 Matrix{Complex{Int64}}:
1+0im 2+0im
3+0im 0+4im
- エルミート共役
A'
2×2 adjoint(::Matrix{Complex{Int64}}) with eltype Complex{Int64}:
1+0im 3+0im
2+0im 0-4im
- 行列の代数演算でエルミート行列を作る
(A + A') / 2
2×2 Matrix{ComplexF64}:
1.0+0.0im 2.5+0.0im
2.5+0.0im 0.0+0.0im
8. 辞書型 Dict
help?> Dict
search: Dict TypeDict IdDict WeakKeyDict SubtypeDict AbstractDict MakeTypeDict
Dict([itr])
Dict{K,V}() constructs a hash table with keys of type K and values of type
V. Keys are compared with isequal and hashed with hash.
Given a single iterable argument, constructs a Dict whose key-value pairs
are taken from 2-tuples (key,value) generated by the argument.
8.1 辞書を使う
辞書型の宣言を Julia で行うには Dict()
を使います.
対応の始め,いわば辞典の単語を key といい,対応の終わり,いわば単語の意味を value といいます.
比喩の部分は個々の事例ごとに「人の名前と試験の点数」などになったりします.
Array
と異なるのはこの対応の関係です.
辞書への追加は模式的には Dictionary["key"] = value
のように行えます.4 5
push!()
でもできます.
begin
D = Dict{String, String}([])
D["author"] = "Aristotle"
push!(D, "A" => "Any")
@show D
end
# D = Dict("A" => "Any", "author" => "Aristotle")
辞書は類を作るのに役立ちます.
例えば本当の辞書や索引のように 頭文字のアルファベットによる類別を書いてみましょう.
シングルクォーテーションマーク '
は特別なタイプ Char
を用意します.6 7
Dict('A' => Set(["Alain Aspect", "Antonín Dvořák"]))
# Dict{Char, Set{String}} with 1 entry:...
8.2 辞書の応用
次にこの手法を応用してみましょう.
類のタイプを Set
から Vector
に変え,更に内包の for
のベクトルから辞書を作ってみます.
Dict([(alphabet, Vector{Type}([])) for alphabet in 'A':'Z'])
# Dict{Char, Vector{Type}} with 26 entries:...
このようなやり方で,型のすべてのサブタイプを格納する辞書を作ってみましょう.
#%% application of a dictionary
function nextsubtype!(T, V)# recurrence
push!(V, T)
for t in subtypes(T)
nextsubtype(t, V)
end
# ref. https://en.wikibooks.org/wiki/Introducing_Julia/Types
end
function allsubtypes(T)# vector of types
V = Vector{Type}()
nextsubtype!(T, V)
return V
end
function SubtypeDict(T)
X = allsubtypes(T)# vector of types
S = Set([string(x)[1] for x in X])# alphabets
DictOfTypes = Dict([(s, Vector{Type}([])) for s in S])
for x in X
push!(DictOfTypes[string(x)[1]], x)
end
return DictOfTypes
end
T = Number
_ans = SubtypeDict(T)
display(_ans)
open("SubtypeDict" * string(T) * ".txt", "w") do f
write(f, repr("text/plain", _ans))
end
display
の結果は text データとして保存すれば環境に依存せず全体をそのまま見ることができます.8 9
Dict{Char, Vector{Type}} with 9 entries:
'B' => [BigFloat, Bool, BigInt]
'F' => [Float16, Float32, Float64]
'U' => [Unsigned, UInt128, UInt16, UInt32, UInt64, UInt8]
'A' => [AbstractFloat, AbstractIrrational]
'I' => [Irrational, Integer, Int128, Int16, Int32, Int64, Int8]
'R' => [Real, Rational]
'S' => [Signed]
'N' => [Number]
'C' => [Complex]
ソートしたい場合は以下のようにします.10
sort(collect(_ans), by = x->x[1])
9-element Vector{Pair{Char, Vector{Type}}}:
'A' => [AbstractFloat, AbstractIrrational]
'B' => [BigFloat, Bool, BigInt]
'C' => [Complex]
'F' => [Float16, Float32, Float64]
'I' => [Irrational, Integer, Int128, Int16, Int32, Int64, Int8]
'N' => [Number]
'R' => [Real, Rational]
'S' => [Signed]
'U' => [Unsigned, UInt128, UInt16, UInt32, UInt64, UInt8]
_ans
は引き継がれています.
9. 型をもっと学ぶ*
9.1 Abstract Types*
型の包含関係を見て Julia の理解を含めましょう.
例えば Rational
は Real
の直下にあってサブタイプを持ちません.
supertype(Rational)# Real
subtypes(Rational)# Type[]
Real
は Number
の直下にあります.
subtypes(Number)# 2-element Vector{Any}:
2-element Vector{Any}:
Complex
Real
すべてのタイプの上には Any
があります.
subtypes(Any)# 611-element Vector{Any}: (Default)
supertype(Any)# Any
9.2 型のグラフを書く**
型の全貌をグラフにしてみましょう.
Any
の自己ループを除けばグラフは木 (tree) になるはずで再帰的に書いています.
主要部は以下です.
function showtypetree(T, io, level=0, tab=8)
ladder = "ᴸ" * repeat("-", 3)
...
println(T)
write(io, string(T) * "\n")
for t in subtypes(T)
showtypetree(t, io, level+1)# recurrence
end
# https://en.wikibooks.org/wiki/Introducing_Julia/Types
end
2行目は鍵型の字は Unicode の中から中央の L を選びました.11
-
結果を保存したレポジトリです.
→ Krypf/20230320Qiita: Julia basics -
9割は
Function
のサブタイプです.using
などでパッケージを入れるともっと増えます.
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
10. おわりに
Julia における型を学びました.
Julia は Python と同じく動的型付け言語です.しかし Python とは異なり Julia では TypeError に対処する機会が多くあります.
従って型の理解は必ず身につけて置かなければなりません.
この制約は一見枷のようにも思えます.でもこうした枠 (組み) が却ってコードの方向性や速度に寄与し決定することもあるのではないでしょうか.
譬えれば言語にはこんな特性があります:12 13
- C/C++ (/C#), レールの上をひた走る鉄道.速い.でも同じ街の中を移動するのには必要ない.
- Python, バスや自家用車といった車.既製品 (パッケージ) 多数.拡張性◎.鉄道よりは遅い.
- MATLAB, ヘリコプター.構造 (構文) は簡単.操縦 (ファイル管理) が面倒.特定の導線 (線型代数) では高速.ヘリポートが必要.(客として)簡単に乗れない.
- Julia, (自家用) 飛行機.海外に行くにはとても速い.滑走路が必要.国内移動程度なら C/C++ で足りることもある.用途を選ぶ.空港 (パッケージ) がない地域も多い.
このように,Julia は C 系言語よりは制約はある種少ない上に,Python より激烈に速く,(比喩を離れて) 実際上は Python/MATLAB からの移行の学習コストはほぼ0に等しいわけです.
また C 系の (言語で食べてきた) プログラマ(エンジニア)が喧伝するほどに静的型付けの絶対性に固執する必要もないと僕は思いますし,だからこそ型をある時は堅固ある時は柔軟に扱える動的型付け言語 Julia は高速な数値計算ツールとして最強なのです.
つまり Julia は,プログラムの実行速度の観点からは Python と (ここが大きい),構文の簡明さの観点からは C/C++ と,アクセシビリティの観点からは MATLAB と,互いに補い合える関係にあるということなのです.
(参考)
- Types · The Julia Language
- More about types · The Julia Language
- 型 · The Julia Language
- Introducing Julia/Types - Wikibooks, open books for an open world
- Diagram with all Julia types? - General Usage - Julia Programming Language
- Julia で時間を扱う標準ライブラリ Dates · The Julia Language
-
Python では
1j
です. ↩ -
古いページでは
push!()
は遅いと書かれているときもありますが現在のバージョンJulia Version 1.8.5
では自分で変なことを考えるよりもfor
文とpush!()
の方が速いコードもあります. ↩ -
数列は写像として定義する場合とその値として定義する場合があります. ↩
-
How to create strings combining all letters? - General Usage - Julia Programming Language ↩
-
Generate all words of a given size from a fixed alphabet - General Usage - Julia Programming Language ↩
-
How do I sort a dictionary by its keys? - New to Julia - Julia Programming Language ↩
-
言語特性の譬え話は昔からあります.Fortran は第3世代最強の呼び声高いプテラ (かせきポケモン) です.18のプログラミング言語をポケモンに例えてみた! | TechAcademyマガジン ↩
-
譬え話で観るブラウザ戦争.納得?5つのブラウザを乗り物で表現すると…:らばQ ↩