整数と浮動小数点数

整数と浮動小数点値は、演算処理の基本的要素です。コード内の即値としての整数と浮動小数点値の表現は 数値リテラルとして知られている一方で、ビルトインのこれらの値の表現は数値プリミティブと呼ばれています。 例えば、 1 は整数リテラルですが、1.0 は浮動小数点リテラルです。これらのオブジェクトとしての インメモリ表現が数値プリミティブです。

Juliaは、幅広いプリミティブ数値型を提供し、標準的な数学関数はもちろん算術演算やビット演算子の 補完が定義されています。これらは、現代のコンピュータでサポートされている数値型や演算処理と関連づけます。 これにより、Juliaは演算処理のリソースを最大限活用することができます。さらに、Juliaは、 使用しているハードウェアでは効果的に表現できない数値の演算処理を行うことができる 任意精度計算 の ソフトウェアサポートを提供します。

以下はJuliaにおける数値プリミティブ型です。

型   符号の有無バイト数最小値最大値
Int88-2^72^7 - 1
UInt8802^8 - 1
Int1616-2^152^15 - 1
UInt161602^16 - 1
Int3232-2^312^31 - 1
UInt323202^32 - 1
Int6464-2^632^63 - 1
UInt646402^64 - 1
Int128128-2^1272^127 - 1
UInt12812802^128 - 1
BoolN/A8false (0)true (1)
型  精度バイト数     
Float16half16
Float32single32
Float64double64

加えて、複素数と有理数 へのサポートは、これらの数値プリミティブ型を踏まえて構築されています。 全ての数値型は、明示的に割り当てることなく自然に相互運用します。:type promotion system

整数

整数リテラルは標準的な方法で表現されます。:

julia> 1
1

julia> 1234
1234

整数リテラルのデフォルトの型は、ターゲットシステムのアーキテクチャが32ビットであるか 64ビットであるかによって異なります。:

# 32-bit system:
julia> typeof(1)
Int32

# 64-bit system:
julia> typeof(1)
Int64

Juliaの内部変数 Sys.WORD_SIZE はターゲットシステムが32ビットまたは64ビットのどちらかであることを示します。:

# 32-bit system:
julia> Sys.WORD_SIZE
32

# 64-bit system:
julia> Sys.WORD_SIZE
64

Juliaは、システムの符号つきまたは符号なしの固有の整数型のエイリアスである Int および UInt 型を定義します。:

# 32-bit system:
julia> Int
Int32
julia> UInt
UInt32

# 64-bit system:
julia> Int
Int64
julia> UInt
UInt64

32ビットを使用して表現できないが、64ビットでは表現できるような大きな整数リテラルの場合、 システムタイプに関係なく常に64ビット整数を作成します。:

# 32-bit or 64-bit system:
julia> typeof(3000000000)
Int64

符号なし整数は、 0x プレフィックスおよび16進数の 0-9a-f (大文字の A-F は入力時のみ使用可能)を 使用して入力および出力されます。符号なしの値の大きさは、使用されている16進数の桁数により決定されます。:

julia> 0x1
0x01

julia> typeof(ans)
UInt8

julia> 0x123
0x0123

julia> typeof(ans)
UInt16

julia> 0x1234567
0x01234567

julia> typeof(ans)
UInt32

julia> 0x123456789abcdef
0x0123456789abcdef

julia> typeof(ans)
UInt64

この動作は、整数値に符号なし16進リテラルを使用する際、ただの整数ではなく、 通常固定された数値のバイト列を表すという傾向に基づいています。

前述の通り、変数 ans は対話セッションで最後に出力された式の値がセットされます。 この処理は、Juliaコードがその他の方法で実行された場合には実施されません。

2進および8進リテラルについてもサポートされています。:

julia> 0b10
0x02

julia> typeof(ans)
UInt8

julia> 0o10
0x08

julia> typeof(ans)
UInt8

整数のような数値プリミティブ型の最小値と最大値は、 typemin() および typemax() 関数により取得が可能です。:

julia> (typemin(Int32), typemax(Int32))
(-2147483648, 2147483647)

julia> for T in [Int8,Int16,Int32,Int64,Int128,UInt8,UInt16,UInt32,UInt64,UInt128]
           println("$(lpad(T,7)): [$(typemin(T)),$(typemax(T))]")
       end
   Int8: [-128,127]
  Int16: [-32768,32767]
  Int32: [-2147483648,2147483647]
  Int64: [-9223372036854775808,9223372036854775807]
 Int128: [-170141183460469231731687303715884105728,170141183460469231731687303715884105727]
  UInt8: [0,255]
 UInt16: [0,65535]
 UInt32: [0,4294967295]
 UInt64: [0,18446744073709551615]
UInt128: [0,340282366920938463463374607431768211455]

typemin() および typemax() の戻り値は常に指定された引数の型となります。 (上記の式は、まだ紹介されていない for loopsStringsInterpolation などの機能が含まれていますが、プログラミング経験者にとっては難しいものではないはずです。)

オーバーフロー処理

Juliaでは、指定された型の表現可能な最大値を超えた場合、ワードラップが発生します。:

julia> x = typemax(Int64)
9223372036854775807

julia> x + 1
-9223372036854775808

julia> x + 1 == typemin(Int64)
true

このように、Juliaにおける整数の演算は、 合同算術 の 形をとります。これは現代のコンピュータで実行される基本演算の特性を反映しています。 オーバーフローを許容するアプリケーションでは、オーバーフローにより発生したワードラップの明示的なチェックは不可欠です。 チェックが難しい場合は、任意精度計算BigInt 型を使用することをお勧めします。

助産処理エラー

整数の除算(div 関数)には、0で割る、最小の負の数( typemin() )を−1で割るの2つの 例外的ケースがあります。どちらの結果も DivideError となります。余りおよび絶対値の 関数(rem および mod )についても、その第二引数が0の際に DivideError となります。

浮動小数点数

浮動小数点数リテラルは標準的な形式で表されます。:

julia> 1.0
1.0

julia> 1.
1.0

julia> 0.5
0.5

julia> .5
0.5

julia> -1.23
-1.23

julia> 1e10
1.0e10

julia> 2.5e-4
0.00025

上記の結果は、全て Float64 値です。リテラル Float32 値は、 f の代わりに e を使用することで入力が可能です。:

julia> 0.5f0
0.5f0

julia> typeof(ans)
Float32

julia> 2.5f-4
0.00025f0

値は簡単に Float32 に変換することが可能です。:

julia> Float32(-1.5)
-1.5f0

julia> typeof(ans)
Float32

16進数の浮動小数点リテラルも有効ですが、 Float64 値としてのみ使用が可能です。:

julia> 0x1p0
1.0

julia> 0x1.8p3
12.0

julia> 0x.4p-1
0.125

julia> typeof(ans)
Float64

半制度浮動小数点数もサポートされていますが( Float16 )、保存形式のみとして使用が可能です。 計算時には、それらは Float32 に変換されます。:

julia> sizeof(Float16(4.))
2

julia> 2*Float16(4.)
Float16(8.0)

アンダースコア( _ )は桁区切り文字として使用することができます。

julia> 10_000, 0.000_000_005, 0xdead_beef, 0b1011_0010
(10000, 5.0e-9, 0xdeadbeef, 0xb2)

浮動小数点における0

浮動小数点数には 2つの0 (正の0と負の0)があります。 この2つの0は同じ値ですが、 bits 関数を使用した際に見られるように、それぞれ異なるバイナリ表現を持ちます。:

julia> 0.0 == -0.0
true

julia> bits(0.0)
"0000000000000000000000000000000000000000000000000000000000000000"

julia> bits(-0.0)
"1000000000000000000000000000000000000000000000000000000000000000"

特殊な浮動小数点値

実数直線上に対応しない3つの浮動小数点値が存在します。

Float16Float32Float64名称概要
Inf16Inf32Inf 正の無限大      全ての有限の浮動小数点値よりも大きい値
-Inf16-Inf32-Inf負の無限大全ての有限の浮動小数点数値よりも小さい値
NaN16NaN32NaN非数値浮動小数点値以外の値

どのように非有限浮動小数点値がお互いに、およびその他の浮動値に対して順序付けられているかについては、 を参照してください。 IEEE 754規格 では、これらの浮動小数点値は特定の演算処理の結果として取得されます。:

julia> 1/Inf
0.0

julia> 1/0
Inf

julia> -5/0
-Inf

julia> 0.000001/0
Inf

julia> 0/0
NaN

julia> 500 + Inf
Inf

julia> 500 - Inf
-Inf

julia> Inf + Inf
Inf

julia> Inf - Inf
NaN

julia> Inf * Inf
Inf

julia> Inf / Inf
NaN

julia> 0 * Inf
NaN

typemin() および typemax() 関数は浮動小数点型に対しても使用が可能です。

julia> (typemin(Float16),typemax(Float16))
(-Inf16, Inf16)

julia> (typemin(Float32),typemax(Float32))
(-Inf32, Inf32)

julia> (typemin(Float64),typemax(Float64))
(-Inf, Inf)

計算機エプシロン

ほとんどの実数は、浮動小数点数で正確に表現することができないため、計算機イプシロン として知られる隣接する2つの浮動小数点数の距離を理解することは、多くの用途のために重要となります。

Juliaは、 1.0 と次に大きい浮動小数点値の間の距離を取得する eps() 関数を提供しています。:

julia> eps(Float32)
1.1920929f-7

julia> eps(Float64)
2.220446049250313e-16

julia> eps() # same as eps(Float64)
2.220446049250313e-16

これらはそれぞれ Float32 および Float64 値として 2.0^-23 および 2.0^-52 と なります。 eps() 関数は、浮動小数点値を引数として使用したり、ある値と次の浮動小数点値との絶対差を 得ることができます。つまり、 eps(x)x と同様の型の値を生成し、x + eps(x)x よりも 大きい次の浮動小数点値を生成します。:

julia> eps(1.0)
2.220446049250313e-16

julia> eps(1000.)
1.1368683772161603e-13

julia> eps(1e-27)
1.793662034335766e-43

julia> eps(0.0)
5.0e-324

隣接する2つの浮動小数点数の距離は一定ではありませんが、小さい値ではその距離はより小さく、 大きい値ではより大きくなります。言い換えれば、浮動小数点数は実数線上で0に近い場合に最も高密度になり、 0から離れるにつれてまばらになっていきます。定義上、 1.0 は64ビットの浮動小数点値であるため、 eps(1.0)eps(Float64) と同一です。

Juliaは、次の最大または最小の浮動小数点数を引数に戻り値として与える nextfloat() および prevfloat() 関数を提供しています。:

julia> x = 1.25f0
1.25f0

julia> nextfloat(x)
1.2500001f0

julia> prevfloat(x)
1.2499999f0

julia> bits(prevfloat(x))
"00111111100111111111111111111111"

julia> bits(x)
"00111111101000000000000000000000"

julia> bits(nextfloat(x))
"00111111101000000000000000000001"

この例では、隣接する浮動小数点数は隣接する二進整数を持つという一般的な原則を表しています。

端数処理モード

値が割り切れる浮動小数点数ではない場合、適切な表現可能な値に繰り上げる必要があります。 しかし、必要な場合は、どのように繰り上げするかは IEEE 754規格 の 端数処理モードに準拠して変更が可能です。

julia> x = 1.1; y = 0.1;

julia> x + y
1.2000000000000002

julia> setrounding(Float64,RoundDown) do
           x + y
       end
1.2

デフォルトでは、偶数の最下位ビットに最も近い値になるよう値を 繰り上げる RoundNearest が常に使用されます。

Warning

端数処理は通常基本的な算術関数(+()-()*()/()sqrt())および 型変換処理においてのみ正常に機能します。その他の多くの関数は、デフォルトの RoundNearest モードが 設定されている前提で機能し、その他の端数処理モードでの演算処理では誤った結果を出力する場合があります。

背景と考察

浮動小数点数演算は、あまり経験のないユーザには難しいかもしれませんが、多くの応用的な知識が必要です。 しかし、応用的な知識は科学技術計算に関する書籍や以下参考に詳細が記載されています。

任意精度計算

任意精度の整数と浮動小数点数の計算を可能にするため、Juliaは GNU Multiple Precision Arithmetic Library (GMP) および GNU MPFR Library に対応しています。Juliaでは任意精度整数と浮動小数点数のための The BigInt および BigFloat 型を利用いただけます。

コンストラクタは数値プリミティブ型からこれらの型を生成し、parse()AbstractStringから これらの型を生成する際に使用できます。Juliaの 型プロモーションと変換機構 type promotion and conversion mechanism により、一度生成すると、全ての数値型で演算に対応します。

julia> BigInt(typemax(Int64)) + 1
9223372036854775808

julia> parse(BigInt, "123456789012345678901234567890") + 1
123456789012345678901234567891

julia> parse(BigFloat, "1.23456789012345678901")
1.234567890123456789010000000000000000000000000000000000000000000000000000000004

julia> BigFloat(2.0^66) / 3
2.459565876494606882133333333333333333333333333333333333333333333333333333333344e+19

julia> factorial(BigInt(40))
815915283247897734345611269596115894272000000000

しかし、上記のプリミティブ型と BigInt または BigFloat 間の型変換は、自動では行われず、 明示的に指定する必要があります。

julia> x = typemin(Int64)
-9223372036854775808

julia> x = x - 1
9223372036854775807

julia> typeof(x)
Int64

julia> y = BigInt(typemin(Int64))
-9223372036854775808

julia> y = y - 1
-9223372036854775809

julia> typeof(y)
BigInt

デフォルトの精度(仮数のビット数で設定)および BigFloat 関数の端数処理は、setprecision() および setrounding() を使用することで設定変更が可能です。設定変更後の演算は全てこの変更が反映されます。 また、コード内の特定のブロックのみの精度や端数処理の変更をしたい場合は、 do ブロックを併用することで設定が可能です。:

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では乗算の数値リテラルが変数を 先行することができます。これにより多項式をより明確に記載することができます。:

julia> x = 3
3

julia> 2x^2 - 3x + 1
10

julia> 1.5x^2 - .5x + 1
13.0

また、指数関数を簡潔に記載することが可能です。:

julia> 2^2x
64

数値リテラル係数の優先順位は、否定のような単項演算子と同様です。 2^3x2^(3x) として 解析され、 2x^32*(x^3) として解析されます。:

数値リテラルは括弧内の式の係数としての役割も持ちます。:

julia> 2(x-1)^2 - 3(x-1) + 1
3

さらに、括弧内の式は、変数の式の乗数を示す変数の係数としても使用できます。:

julia> (x-1)x
6

2つの括弧内の式の並記や括弧を伴う式の前に変数の置くことは、乗算を意味するためには使用することができません。

julia> (x-1)(x+1)
ERROR: MethodError: objects of type Int64 are not callable

julia> x(x+1)
ERROR: MethodError: objects of type Int64 are not callable

上記2つの式は関数として解釈されています。括弧を伴う式が直後に続く数値リテラルではない式は、 括弧内の値に適用される関数として解釈されます(詳細は Functions を参照ください)。 上記の例では、左辺の値が関数ではないため、エラーが発生します。

上記の構文の拡張機能は、同様な数式を記載する際の視覚的なノイズを低減します。 数値リテラル係数と乗算識別子や括弧で囲まれた式の間には、空白を入れることができませんので、注意してください。

構文の競合

並列されたリテラル係数の構文は、16進整数リテラルと浮動小数点リテラルの指数表記の2つの 数値リテラルと競合する場合があります。以下は構文の競合が発生する状況の例です。

上記両ケースでは、優先的に数値リテラルとして解釈されるようにすることで、あいまいさを回避しています。

リテラルの0および1

Juliaは、特定の方や特定の変数の型に対応してリテラル0および1を返す関数を提供しています。

関数    D概要
zero(x)x 型のリテラル0または変数 x の型
one(x)x のリテラル1型または変数 x の型

これらの関数は、 時の不要な type conversionの オーバーヘッドを回避する際に有効です。

例:

julia> zero(Float32)
0.0f0

julia> zero(1.0)
0.0

julia> one(Int32)
1

julia> one(BigFloat)
1.000000000000000000000000000000000000000000000000000000000000000000000000000000