Juliaは汎用言語で、ほとんどのプログラミング作業に使うことができます。 しかし実際には、主な用途は工学と科学の分野に偏りがちです。 高速で柔軟、かつ高度な数値計算が、設計の中心にあります。
整数とは、小数点のない「丸い」数値のことです。
Basicsのコンセプトでは、型を指定しなくても整数値を変数に代入できることを見ました。
可読性のために、アンダースコアを桁区切りとして使うことができます。 これはコンパイラーに無視されます。
julia> x = 3
3
julia> typeof(x)
Int64
julia> large_number = 1_234_567_890
1234567890
内部的には、コンパイラーはCPUにとって最も適切な符号付き整数型を使用します。
現代のPCでは通常Int64になり、ほとんどの作業に十分です。
型については、今後のコンセプトでより詳しく説明します。 今のところは、このドキュメントを理解するのに_数値_型が十分に直感的であれば大丈夫です。
後のコンセプトで見るように、Juliaは非常に大きな多次元配列をネイティブにサポートしています。 これは、利用可能なメモリ量とデータ転送の帯域幅の両方を圧迫する可能性があります。
プログラマーにもっと細かい制御を与えるために、符号付きまたは符号なしの整数型を指定することが可能で、よく行われてもいます。 以前にPythonを使ったことのある多くのJulia学習者は、これを素のPythonではなくNumPyと比較するとよいでしょう。
julia> y = Int8(42)
42
julia> typeof(y)
Int8
julia> z = UInt32(1024)
0x00000400
Juliaは符号なし整数をデフォルトで16進数形式で表示することに注意してください。符号なし型は低レベルのビット演算によく使われるためです。
整数は2進数、8進数、16進数として入力することもでき、それぞれ接頭辞0b、0o、0xを付けます。
julia> a = 0x10
0x10
julia> Int(a)
16
julia> b = 0b1010 # displays as hexadecimal
0x0a
BigInt
それぞれの整数型には、格納できる最大値と最小値があります。
julia> typemax(Int8)
127
julia> typemin(Int8)
-128
この有効範囲を外れると整数オーバーフローが発生し、非常に奇妙に見える結果になります。
julia> c = Int8(126)
126
julia> c * c
4
126 * 126が4に_ならない_ことには、おそらく同意できるでしょう!
詳しい説明には、CPUのレジスタが整数をどう格納するかという知識が必要で、これはこのコンセプトの範囲外です。
この問題は、より「幅の広い」型を使えば最小限に抑えられます。Int128やUInt128まであります(「幅の広い」の意味は後述します)。 ただし、どの型にも、オーバーフローの問題に直面する前に厳しい限界があります。
一つの解決策はBigInt型を使うことで、これはコンピューターのメモリによってのみ制限されます。
これは任意精度演算のJuliaにおける実装です。
julia> 2 ^ 70
0
julia> big = BigInt(2) ^ 70
1180591620717411303424
julia> UInt128(big)
0x00000000000000400000000000000000
2の70乗はInt64に収まらないため、上の例の最初の計算は失敗します。ただし、_エラーメッセージは出ない_ことに注意してください。
プログラマーは用心してください!
2をBigIntにキャストすると正しい答えが得られ、16進数で表示すると、これが2の累乗であることがより明確になります。
浮動小数点数が、小数点と小数点以下の小数部分を任意で持つことは、驚きではないでしょう。
julia> f = 3.45
3.45
julia> typeof(f)
Float64
もちろん、指数表記もサポートされています。
julia> avogadro = 6.02e23
6.02e23
整数と同様、デフォルトの型はほとんどの用途で問題ありませんが、他の符号付き型も利用できます。 _符号なし_浮動小数点型はありません。
ショートカットとして、f0接尾辞を使うとFloat32の値を作成できます。
julia> f32 = 4.56f0
4.56f0
julia> typeof(f32)
Float32
他のサイズの浮動小数点は、整数と同様に明示的なキャストが必要です。
最大値と最小値は驚きかもしれません。
julia> typemax(Float64)
Inf
julia> typemin(Float64)
-Inf
無限大は有効な値です!
ただし、浮動小数点数の実用的な範囲には限りがあり、非常に大きな値は単にInfが割り当てられ、非常に小さな値は0.0に丸められます。
別の関数のペアを使うと、これらの限界を確認できます。おおよそ± 10 ^ 308です。
julia> floatmax(Float64)
1.7976931348623157e308
julia> floatmin(Float64)
2.2250738585072014e-308
また、精度にも限りがあり、有効数字は大きくても有限の個数しか表現できません(Float64では約15桁)。
Basicsのコンセプトで説明したように、算術演算子は、子どもに教えるような標準的な算術とほとんど同じように機能します。
べき乗には^を使い、**は使いません(どちらも他の言語では一般的です)。
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
3.3333333333333335
julia> div(10, 3)
3
julia> 10 ÷ 3
3
julia> 10 // 3
10//3
div()関数は整数の割り算用で、結果は0に向かって切り捨てられます。正の数では下方向、負の数では上方向です。
同義語として中置演算子÷も使え、これもより数学的に見せることを狙っています。
Juliaに対応したエディターを使っているなら、\divと入力してから<Tab>キーを押します。
//演算子には、シラバスの後の方で独自のコンセプトが必要です。
今のところは、//の結果は「有理数」だと言っておけば十分です。これは、ほとんどの人が分数と呼ぶものの正式な名前です。
分子と分母から共通因数が取り除かれ、2つの整数の比が、いわゆる「既約形」になります。
julia> rationalnum = 22 // 6
11//3
julia> typeof(rationalnum)
Rational{Int64}
有理数が手に入りました。 では、「無理数」はどうでしょうか?
julia> π
π = 3.1415926535897...
julia> typeof(π)
Irrational{:π}
無理数とは、整数の比に還元できない数のことです。
よくある例としては、π、e(オイラー数)、そして√2(2の平方根)のような多くの累乗根があります。
Juliaは数学を_きちんと_行おうとします。
これはしばしば自動的に行われます。
julia> x = 2 + 3.5
5.5
julia> typeof(x)
Float64
Int64にFloat64を足して、Float64の結果が得られました。
実際には、足し算を行う前に整数が暗黙のうちにFloat64に変換されています。
Juliaには、数値型の「幅」という概念があります。
Int64はInt16より幅が広いです。式の中で複数の型を混ぜて使うと、それぞれが必要に応じて、使われている中で最も幅の広い型に「昇格」されます。
変換を強制するには、Float64(5)のように整数を特定の型にキャストします。
あるいは、単にfloat(5)を使って、適切な型をコンパイラーに選ばせます。
浮動小数点から整数への変換は、必然的により複雑です。 小数点以下の部分をどう扱いたいですか?
round()関数は最も近い整数に変換し、4.5のような中間の場合は最も近い_偶数_の整数に丸めます。floor()は下方向に、ceil()は上方向に、trunc()は0に向かって丸めます。Int32()などで直接キャストしようとすると、InexactErrorで失敗します。ただし、デフォルトではこれらの関数は、望んだかもしれない整数型を返しません。 出力したい型を指定できます。
julia> round(4.5)
4.0
julia> round(Int64, 4.5)
4
julia> round(Int, 4.5) # => default integer type
4
julia> ceil(Int16, 4.3)
5
小数点以下の桁数を指定して丸めることも、digitsキーワードで可能です。
julia> round(π, digits=10)
3.1415926536
詳しくはマニュアルを参照してください。
これは単にエラーになるだけではないでしょうか? 実際には、話はそれほど単純ではありません。
÷や//による整数の割り算は、予想どおりエラーになります。
/による浮動小数点の割り算は、標準的なコンピューターサイエンスのアプローチではなく、工学的なアプローチとでも言うべきものを取ります。
julia> 2 / 0
Inf
julia> 0 / 0
NaN
前のセクションで説明したように、無限大はJuliaでは有効な浮動小数点数で、Infで表されます。
分子もゼロの場合、結果は数学的に未定義です。
そのときJuliaはこれを「非数」として扱い、NaNで表します。
これが奇妙に思えるなら、現実世界の(したがってしばしばかなり雑然とした)データの大きな配列を扱う場面を考えてみてください。 先に進むには、問題のある値に印を付けて先へ進むのが一番です。
値を延々と手作業でチェックするのはプログラムするのも退屈ですし、実行時のパフォーマンスを確実に損ないます。
ちょっとした不具合のたびにエラーメッセージで停止するプログラムは、ユーザーから_とても_嫌われます!
Conditionalsのコンセプトで説明したように、等値判定は通常==演算子で行います。
これは整数、文字、文字列などではうまく機能します。
しかし、浮動小数点値は精度が限られており、同じ結果を計算する方法が違うと、わずかに異なる値になることがあります。
Float64では、通常15桁目あたりになります。小さな違いですが、「等しい」わけではありません。
伝統的に、プログラマーへの助言は、浮動小数点値に==を_決して_使わないことです。結果が予測できないからです。
広く使われている代替手段は、差の絶対値を、許容される誤差(しばしばイプシロンやϵと呼ばれます)と比較することです。
つまり、a == bの代わりにabs(a - b) < epsilonを使います。
Juliaはisapprox()関数という、よりすっきりした代替手段を提供しています。
絶対許容誤差の場合、構文はisapprox(a, b, atol=epsilon)です。
この場合、atolキーワードが必要です。
相対許容誤差のほうが役立つことがよくあります。
これがデフォルトなので、isapprox(a, b)はrtolに適切な値を選ぼうとします(規則はかなり複雑です)。
相対許容誤差も、比較する値の割合として指定できます。
つまりisapprox(a, b, rtol=0.01)は、値が互いに1%以内にあることをテストします。
いつものJulia流で、デフォルトの場合の同義語となる数学演算子があります。a ≈ bです(演算子は\approxと入力してから<tab>を押します)。
有理数に加えて、シラバスの後半では次のものを扱います。