数学演算と初等関数

Julia は全ての初等算術とビット演算を全てのプリミティブ数値型に対して提供します。加えて多くの標準的な数学関数の効率的でポータブルな実装も提供します。

算術演算子

次の算術演算子は全てのプリミティブ数値型でサポートされます:

名前 説明
+x 単項プラス x をそのまま返す (恒等演算)。
-x 単項マイナス 加算逆元を返す。
x + y 二項プラス 加算の結果を返す。
x - y 二項マイナス 減算の結果を返す。
x * y 乗算 乗算の結果を返す。
x / y 除算 除算の結果を返す。
x ÷ y 整数除算 x / y を整数に切り捨てた値を返す。
x \ y 逆除算 y / x を返す。
x ^ y べき乗 xy 乗を返す。
x % y 剰余 rem(x,y) を返す。

Bool 型の否定もあります:

名前 説明
!x 否定 true に対して false を、false に対して true を返す。

2x2(x+y) のように識別子や括弧に囲まれた式の直前に数値リテラルが置かれると乗算として扱われ、その結合は他の二項演算子より優先度が高くなります。詳しくは数値リテラル係数の節を参照してください。

Julia の型昇格システムにより、算術演算で引数の型を混ぜたとしても自然な動作が自動的に行われます。型の昇格について詳しくは型の変換と昇格の章を参照してください。

算術演算子を使った簡単な例を示します:

julia> 1 + 2 + 3
6

julia> 1 - 2
-1

julia> 3*2/12
0.5

(慣習により、通常私たちは他の演算子よりも早く適用される演算子を詰めて書きます。例えば、私たちは普通 -x + 2 と書きますが、この書き方には x に単項マイナスが最初に適用され、それから 2 が加算されることが表されています。)

false を乗算で使うと、強いゼロ (strong zero) となります:

julia> NaN * false
0.0

julia> false * Inf
0.0

これは値がゼロに確定する場面で NaN を保存・伝播させないために利用できます。強いゼロを導入する動機については Knuth (1992) を参照してください。

ビット演算子

次のビット演算子は全てのプリミティブ整数型でサポートされます:

名前
~x ビット単位の否定
x & y ビット単位の論理積
x | y ビット単位の論理和
x ⊻ y ビット単位の排他的論理和
x >>> y 論理右シフト
x >> y 算術右シフト
x << y 論理/算術左シフト

ビット演算の例を示します:

julia> ~123
-124

julia> 123 & 234
106

julia> 123 | 234
251

julia> 123  234
145

julia> xor(123, 234)
145

julia> ~UInt32(123)
0xffffff84

julia> ~UInt8(123)
0x84

更新演算子

二項の算術演算子と二項のビット演算子は全て更新バージョンの演算子を持ちます。二項演算子の直後に = を付けると更新バージョンの演算子となり、演算の結果が左辺のオペランドに代入されます。例えば、x += 3x = x + 3 と等価です:

julia> x = 1
1

julia> x += 3
4

julia> x
4

更新バージョンの二項演算子は次に示すもので全てです:

+=  -=  *=  /=  \=  ÷=  %=  ^=  &=  |=  ⊻=  >>>=  >>=  <<=
情報

更新演算子は左辺の変数を再束縛します。そのため、変数の型が変わる可能性があります:

julia> x = 0x01; typeof(x)
UInt8

julia> x *= 2 # x = x * 2 と同じ
2

julia> typeof(x)
Int64

ベクトル化演算子 (ドット演算子)

全ての二項演算には、対応する「ドット演算」が存在します。例えばべき乗演算 ^ に対応するドット演算 .^ は配列の各要素に対して ^ を適用する演算であり、他の演算でも同様です。例えば (正方でない) 配列を三乗する標準的な数学操作は存在しないので、[1,2,3] ^ 3 は定義されません。しかし [1,2,3] .^ 3 は要素ごとの (「ベクトル化」) 演算として定義され、[1^3, 2^3, 3^3] が結果となります。同様に ! といった単項演算にも、配列の各要素に対して演算を適用する演算 (.!.√) が存在します。

julia> [1,2,3] .^ 3
3-element Array{Int64,1}:
  1
  8
 27

詳しく言うと a .^ b(^).(a,b) という 「ドット呼び出し」 としてパースされ、ブロードキャスト演算が行われます。ドット呼び出しには配列とスカラーの組あるいは同じサイズの二つの配列の組 (演算を要素ごとに適用する) を渡すことができ、加えて形が異なる配列の組 (行ベクトルと列ベクトルを組み合わせて行列を作る場合など) さえも渡すことができます。

また “ドット呼び出し” によってベクトル化された関数呼び出しと同様に、“ドット演算子” には融合 (fusing) が行われます。例えば配列 A に対して 2 .* A.^2 .+ sin.(A) (あるいは @. マクロを使った等価な式 @. 2A^2 + sin(A)) を計算するとき、Julia は A に対するループを一度だけ行い、各反復で 2a^2 + sin(a)A の各要素に対して計算します。他にも f.(g.(x)) のようなネストされたドット呼び出しでも融合が起こり、さらに x .+ 3 .* x.^2 のような “隣接する” 二項演算子はネストされたドット呼び出し (+).(x, (*).(3, (^).(x, 2))) と等価となります。

さらに、ドットが付いた更新演算を使って a .+= b (あるいは @. a += b) と書くと、a .= a .+ b とパースされます。ここで .= は融合を許すインプレースな代入演算を表します (詳しくはドット構文のドキュメントを参照してください)。

ドット構文はユーザーが定義した演算子にも適用できます。例えば ⊗(A,B) = kron(A,B) としてクロネッカー積 (kron) の中置記法 A ⊗ B を定義したのであれば、他にコードを書かなくても [A,B] .⊗ [C,D][A⊗C, B⊗D] を計算できます。

ドット演算子と数値リテラルを混ぜると曖昧な式になる可能性があります。例えば 1.+x1. + x1 .+ x のどちらを意味するかは明らかではありません。そのためこの書き方は許されておらず、こういった場合には演算子の隣に空白が必要です。

数値の比較

標準的な比較演算は全てのプリミティブ数値型で定義されます:

演算子 名前
== 等号
!=, 等号否定
< 小なり
<=, 小なり等号
> 大なり
>=, 大なり等号

簡単な例を示します:

julia> 1 == 1
true

julia> 1 == 2
false

julia> 1 != 2
true

julia> 1 == 1.0
true

julia> 1 < 2
true

julia> 1.0 > 3
false

julia> 1 >= 1.0
true

julia> -1 <= 1
true

julia> -1 <= -1
true

julia> -1 <= -2
false

julia> 3 < -0.5
false

整数は通常の方法 ──ビットの比較── で比較されます。浮動小数点数は IEEE 754 規格に従って比較されます:

最後の点には驚くかもしれません。例を示します:

julia> NaN == NaN
false

julia> NaN != NaN
true

julia> NaN < NaN
false

julia> NaN > NaN
false

NaN と配列が絡むと、頭が痛くなる結果となることがあります:

julia> [1 NaN] == [1 NaN]
false

Julia には数値が特殊な値かどうかを判定する関数があります。ハッシュキーの比較などで活躍するでしょう:

関数 判定する条件
isequal(x, y) xy は同一か?
isfinite(x) x は有限の値か?
isinf(x) x は無限大か?
isnan(x) x は非数 (not a number) か?

isequalNaNNaN が等しいとみなします:

julia> isequal(NaN, NaN)
true

julia> isequal([1 NaN], [1 NaN])
true

julia> isequal(NaN, NaN32)
true

isequal は正のゼロと負のゼロを区別するのにも使えます:

julia> -0.0 == 0.0
true

julia> isequal(-0.0, 0.0)
false

符号付き整数・符号無し整数・浮動小数点数が混ざる比較は複雑になります。Julia がこの種の比較を正しく行えるよう多くの手間が掛けられてきました。

isequal は浮動小数点数型以外の型に対してデフォルトで == を呼び出します。そのため独自の型に対する等価性を定義するときは == メソッドを追加するだけで済みます。等号関数を独自に定義するときは、対応する hash メソッドも定義して「isequal(x,y) ならば hash(x) == hash(y)」が成り立つようにした方がよいでしょう。

比較の連鎖

多くの言語とは異なり、Julia では (Python と同様に) 比較をいくらでも連鎖できます:

julia> 1 < 2 <= 2 < 3 == 3 > 2 >= 1 == 1 < 3 != 5
true

比較の連鎖は数値計算のコードで非常に有用です。スカラーの比較が連鎖されると && 演算子が使われ、配列の要素ごとの比較が連鎖されると & 演算子が使われます。このため配列の比較も連鎖が可能であり、例えば 0 .< A .< 1 と書くと、0 以上 1 以下の要素に対応する部分が true となった真偽値の配列が手に入ります。

連鎖された比較の評価順序に注意してください:

julia> v(x) = (println(x); x)
v (generic function with 1 method)

julia> v(1) < v(2) <= v(3)
2
1
3
true

julia> v(1) > v(2) <= v(3)
2
1
false

v(1) < v(2) && v(2) <= v(3) と書くと v(2) が二度評価されますが、連鎖させて書くと v(2) は一度しか評価されません。ただし連鎖された比較における評価の順序は未定義です。このため比較の連鎖では副作用 (文字の出力など) を含む式を使わないことが強く推奨されます。もし副作用が必要なら、短絡評価が保証されている && を明示的に使うべきです (短絡評価の節を参照してください)。

初等関数

Julia は数学的な関数と演算子を幅広く取り揃えています。こういった数学演算は定義が可能な限りなるべく広い数値に対して定義されており、整数・浮動小数点数・有理数・複素数をはじめとした定義が意味を持つ全ての数値に対して値を返します。

さらに、こういった数学関数は (他の Julia 関数と同様) “ベクトル化” して配列などのコレクションに適用できます。この適用にはドット構文 f.(A) を使います。例えば sin.(A) は配列 A の各要素のサインを計算します。

演算子の優先順位と結合性

Julia が持つ一部の演算子の優先順位と結合性を次に示します。優先順位が高い演算子から低い演算子に向かって示されています:

カテゴリ 演算子 結合性
構文 ., :: (この順序)
べき乗 ^
単項演算 + - √ 1
ビットシフト << >> >>>
分数 //
乗算 * / % & \ ÷ 2
加算 + - | ⊻ 3
構文 : ..
構文 |>
構文 <|
比較 > < >= <= == === != !== <: 非結合
制御構造 &&, ||, ? (この順序)
=>
代入 = += -= *= /= //= \= ^= ÷=
%= |= &= ⊻= <<= >>= >>>=

Julia が持つ全ての演算子の優先順位の完全なリストは src/julia-parser.scm の先頭部分にあります。

2x のような 数値リテラル係数は他の二項演算子よりも優先度の高い乗算として扱われ、^ よりも高い優先度を持ちます。

演算子の優先度を表す数値は組み込み関数 Base.operator_precedence で確認できます。この値が高い演算子が優先されます:

julia> Base.operator_precedence(:+), Base.operator_precedence(:*), Base.operator_precedence(:.)
(11, 12, 17)

julia> Base.operator_precedence(:sin), Base.operator_precedence(:+=), Base.operator_precedence(:(=))  # :(=) には括弧が必要
(0, 1, 1)

演算子の結合性を示すシンボルは組み込み関数 Base.operator_associativity で確認できます:

julia> Base.operator_associativity(:-), Base.operator_associativity(:+), Base.operator_associativity(:^)
(:left, :none, :right)

julia> Base.operator_associativity(:⊗), Base.operator_associativity(:sin), Base.operator_associativity(:→)
(:left, :none, :right)

:sin のようなシンボルに対する優先度が 0 になることに注意してください。これは不正な演算子を表すのであって、優先度が最低の演算子を表すのではありません。同様に、不正な演算子は :none の結合性を持ちます。

数値の変換

Julia では数値の変換に三つの種類があります。それぞれ正確でない変換の取り扱いが異なります。

様々な変換方法を次の例に示します:

julia> Int8(127)
127

julia> Int8(128)
ERROR: InexactError: trunc(Int8, 128)
Stacktrace:
[...]

julia> Int8(127.0)
127

julia> Int8(3.14)
ERROR: InexactError: Int8(3.14)
Stacktrace:
[...]

julia> Int8(128.0)
ERROR: InexactError: Int8(128.0)
Stacktrace:
[...]

julia> 127 % Int8
127

julia> 128 % Int8
-128

julia> round(Int8,127.4)
127

julia> round(Int8,127.6)
ERROR: InexactError: trunc(Int8, 128.0)
Stacktrace:
[...]

独自の変換と昇格を定義する方法については型の変換と昇格の章を参照してください。

丸め関数

関数 説明 返り値の型
round(x) x を一番近い整数に丸める。 typeof(x)
round(T, x) x を一番近い整数に丸める。 T
floor(x) x-Inf に向かって丸める。 typeof(x)
floor(T, x) x-Inf に向かって丸める。 T
ceil(x) x+Inf に向かって丸める。 typeof(x)
ceil(T, x) x+Inf に向かって丸める。 T
trunc(x) x を 0 に向かって丸める。 typeof(x)
trunc(T, x) x を 0 に向かって丸める。 T

除算関数

関数 説明
div(x,y), x÷y 切り捨て除算: 商は 0 に向かって丸める。
fld(x,y) 床除算: 商は -Inf に向かって丸める。
cld(x,y) 天井除算: 商は +Inf に向かって丸める。
rem(x,y) 剰余: x == div(x,y)*y + rem(x,y) が成り立ち、rem(x,y) の符号は x と一致する。
mod(x,y) モジュロ: x == fld(x,y)*y + mod(x,y) が成り立ち、mod(x,y) の符号は y と一致する。
mod1(x,y) オフセット 1 のモジュロ: mod(r, y) == mod(x, y) を満たす r が返る。y > 0 なら r∈(0,y] となり、y < 0 なら r∈[y,0) となる。
mod2pi(x) 2pi に関するモジュロ: 0 <= mod2pi(x) < 2pi が成り立つ。
divrem(x,y) (div(x,y),rem(x,y)) を返す。
fldmod(x,y) (fld(x,y),mod(x,y)) を返す
gcd(x,y...) x, y,... の正の最大公約数を返す。
lcm(x,y...) x, y,... の正の最小公倍数を返す。

符号関数と絶対値関数

関数 説明
abs(x) x と同じ大きさを持つ正の値を返す。
abs2(x) x の大きさの二乗を返す。
sign(x) x の符号を返す: -1, 0, +1 のいずれかが返る。
signbit(x) 符号ビットが立っているなら true を、下がっているなら false を返す。
copysign(x,y) 大きさが x と等しく符号が y と等しい値を返す。
flipsign(x,y) 大きさが x と等しく符号が x*y と等しい値を返す。

対数と根号

関数 説明
sqrt(x), √x x の平方根
cbrt(x), ∛x x の三乗根
hypot(x,y) 直角をなすニ辺の長さが xy の直角三角形の斜辺の長さを返す。
exp(x) x の自然対数を返す。
expm1(x) 0 に近い x に対する正確な exp(x) - 1 を返す。
ldexp(x,n) 整数 n に対する x*2^n を効率的に計算して返す。
log(x) x の自然対数を返す。
log(b,x) x の底 b の対数を返す。
log2(x) x の底 2 の対数を返す。
log10(x) x の底 10 の対数を返す。
log1p(x) 0 に近い x に対する正確な log(1 + x) を返す。
exponent(x) 浮動小数点数 x の二進指数部を返す。
significand(x) 浮動小数点数 x の二進仮数部 (マンティッサ) を返す。

hypot, expm1, log1p といった関数が必要な理由については John D. Cook による素晴らしいブログ記事 Math library functions that seem unnecessaryWhat's so hard about finding a hypotenuse? を参照してください。

三角関数と双曲線関数

標準的な三角関数と双曲線関数も全て定義されます:

sin    cos    tan    cot    sec    csc
sinh   cosh   tanh   coth   sech   csch
asin   acos   atan   acot   asec   acsc
asinh  acosh  atanh  acoth  asech  acsch
sinc   cosc

これらは全て引数を一つ受け取る関数であり、唯一 atan だけは二つの引数も受け取ります。二つの引数が与えられるときの atan の動作は古くからある atan2 関数と同じです。

これ以外にも sin(pi*x)cos(pi*x) の計算を正確に行うための sinpi(x) 関数と cospi(x) 関数が提供されます。

三角関数の計算をラジアンではなく弧度法で行うには、関数の後ろに d を付けます。例えば角度 x に対するサインを計算するには sind(x) としてください。弧度法を利用できる三角関数は次の通りです:

sind   cosd   tand   cotd   secd   cscd
asind  acosd  atand  acotd  asecd  acscd

特殊関数

様々な特殊関数がパッケージ SpecialFunctions.jl によって提供されます。


  1. 単項演算子 +- を続けて複数使うときは、演算子 ++, -- との曖昧性を解消するために引数の周りに括弧が必要です。他の単項演算子の組み合わせは右結合としてパースされます。例えば √√-a√(√(-a)) を意味します。[return]

  2. 演算子 +, ++, * は結合性を持ちません。a + b + c+(+(a, b), c) ではなく +(a, b, c) とパースされます。ただし、+(a, b, c, d, ...)*(a, b, c, d, ...) に対するフォールバックメソッドのデフォルトの挙動は左結合の評価です。[return]

  3. 演算子 +, ++, * は結合性を持ちません。a + b + c+(+(a, b), c) ではなく +(a, b, c) とパースされます。ただし、+(a, b, c, d...)*(a, b, c, d...) に対するフォールバックメソッドのデフォルトの振る舞いは左結合の評価です。[return]

日本語 Julia 書籍 (Amazon アソシエイト)
1 から始める Julia プログラミング
Julia プログラミングクックブック―言語仕様からデータ分析、機械学習、数値計算まで
スタンフォード ベクトル・行列からはじめる最適化数学