Julia 数据类型
在编程语言中,都有基本的数学运算和科学计算,它们常用的数据类型为整数和浮点数。另外还有一个"字面量"的术语,字面量(literal)用于表达源代码中一个固定值的表示法(notation),整数、浮点数以及字符串等等都是字面量。
例如:
a=1 // a 是变量,1 是整型字面量 b=1.0 // b 是变量,1.0 是浮点型字面量Julia 提供了很丰富的原始数值类型,并基于它们定义了一整套算术运算操作,另外还提供按位运算符以及一些标准数学函数。
整数类型
下表列出来 Julia 支持的整数类型:
类型 | 带符号? | 比特数 | 最小值 | 最大值 |
---|---|---|---|---|
Int8 | ✓ | 8 | -2^7 | 2^7 – 1 |
UInt8 | 8 | 0 | 2^8 – 1 | |
Int16 | ✓ | 16 | -2^15 | 2^15 – 1 |
UInt16 | 16 | 0 | 2^16 – 1 | |
Int32 | ✓ | 32 | -2^31 | 2^31 – 1 |
UInt32 | 32 | 0 | 2^32 – 1 | |
Int64 | ✓ | 64 | -2^63 | 2^63 – 1 |
UInt64 | 64 | 0 | 2^64 – 1 | |
Int128 | ✓ | 128 | -2^127 | 2^127 – 1 |
UInt128 | 128 | 0 | 2^128 – 1 | |
Bool | N/A | 8 | false (0) | true (1) |
整数字面量形式:
实例
1
julia> 1234
1234
整型字面量的默认类型取决于目标系统是 32 位还是 64 位架构(目前大部分系统都是 64 位):
实例
julia> typeof(1)
Int32
# 64 位系统:
julia> typeof(1)
Int64
Julia 的内置变量 Sys.WORD_SIZE 表明了目标系统是 32 位还是 64 位架构:
实例
julia> Sys.WORD_SIZE
32
# 64 位系统:
julia> Sys.WORD_SIZE
64
Julia 也定义了 Int 与 UInt 类型,它们分别是系统有符号和无符号的原生整数类型的别名。
实例
julia> Int
Int32
julia> UInt
UInt32
# 64 位系统:
julia> Int
Int64
julia> UInt
UInt64
溢出行为
在 Julia 里,超出一个类型可表示的最大值会导致环绕 (wraparound) 行为:
实例
9223372036854775807
julia> x + 1
-9223372036854775808
julia> x + 1 == typemin(Int64)
true
因此,Julia 的整数算术实际上是模算数的一种形式,它反映了现代计算机实现底层算术的特点。在可能有溢出产生的程序中,对最值边界出现循环进行显式检查是必要的。否则,推荐使用任意精度算术中的 BigInt 类型作为替代。
下面是溢出行为的一个例子以及如何解决溢出:
实例
-8446744073709551616
julia> big(10)^19
10000000000000000000
除法错误
在以下两种例外情况下,整数除法会触发 DivideError 错误:- 除以零
- 除以最小的负数
rem 取余函数和 mod 取模函数在除零时抛出 DivideError 错误,实例如下:
实例
ERROR: DivideError: integer division error
Stacktrace:
[1] div at .\int.jl:260 [inlined]
[2] div at .\div.jl:217 [inlined]
[3] div at .\div.jl:262 [inlined]
[4] fld at .\div.jl:228 [inlined]
[5] mod(::Int64, ::Int64) at .\int.jl:252
[6] top-level scope at REPL[52]:1
julia> rem(1, 0)
ERROR: DivideError: integer division error
Stacktrace:
[1] rem(::Int64, ::Int64) at .\int.jl:261
[2] top-level scope at REPL[54]:1
浮点类型
下表列出来 Julia 支持的浮点类型:
类型 | 精度 | 比特数 |
---|---|---|
Float16 | 半精度 | 16 |
Float32 | 单精度 | 32 |
Float64 | 双精度 | 64 |
此外,对复数和有理数的完整支持是在这些原始数据类型之上建立起来的。
浮点数字面量格式表示如下,必要时可使用 E 来表示。
实例
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
注:
在科学计数法中,为了使公式简便,可以用带 E 的格式表示。例如 1.03乘10的8次方,可简写为 "1.03E+08" 的形式,其中 "E" 是 exponent(指数) 的缩写。
上面的结果都是 Float64 类型的值。使用 f 替代 e 可以得到 Float32 类型的字面量:
实例
0.5f0
julia> typeof(x)
Float32
julia> 2.5f-4
0.00025f0
数值可以很容易地转换为 Float32 类型:
julia> x = Float32(-1.5)
-1.5f0
julia> typeof(x)
Float32
也存在十六进制的浮点数字面量,但只适用于 Float64 类型的值。一般使用 p 前缀及以 2 为底的指数来表示:
实例
1.0
julia> 0x1.8p3
12.0
julia> x = 0x.4p-1
0.125
julia> typeof(x)
Float64
Julia 也支持半精度浮点数(Float16),但它们是使用 Float32 进行软件模拟实现的。
julia> sizeof(Float16(4.))
2
julia> 2*Float16(4.)
Float16(8.0)
下划线 _ 可用作数字分隔符:
实例
(10000, 5.0e-9, 0xdeadbeef, 0xb2)
浮点数中的零
浮点数有两种零,正零和负零。它们相互相等但有着不同的二进制表示,可以使用 bitstring 函数来查看:
实例
true
julia> bitstring(0.0)
"0000000000000000000000000000000000000000000000000000000000000000"
julia> bitstring(-0.0)
"1000000000000000000000000000000000000000000000000000000000000000"
特殊的浮点值
有三种特定的标准浮点值不和实数轴上任何一点对应:
Float16 | Float32 | Float64 | 名称 | 描述 |
---|---|---|---|---|
Inf16 | Inf32 | Inf | 正无穷 | 一个大于所有有限浮点数的数 |
-Inf16 | -Inf32 | -Inf | 负无穷 | 一个小于所有有限浮点数的数 |
NaN16 | NaN32 | NaN | 不是一个数 | 一个不和任何浮点值(包括自己)相等(==)的值 |
以下列举了一些浮点数的运算实例:
实例
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
julia> NaN == NaN
false
julia> NaN != NaN
true
julia> NaN < NaN
false
julia> NaN > NaN
false
我们还可以使用 typemin 和 typemax 函数:
实例
(-Inf16, Inf16)
julia> (typemin(Float32),typemax(Float32))
(-Inf32, Inf32)
julia> (typemin(Float64),typemax(Float64))
(-Inf, Inf)
机器精度
大多数实数都无法用浮点数准确地表示,因此有必要知道两个相邻可表示的浮点数间的距离,它通常被叫做机器精度。
Julia 提供了 eps 函数,它可以给出 1.0 与下一个 Julia 能表示的浮点数之间的差值:
实例
1.1920929f-7
julia> eps(Float64)
2.220446049250313e-16
julia> eps() # 与 eps(Float64) 相同
2.220446049250313e-16
这些值分别是 Float32 中的 2.0^-23 和 Float64 中的 2.0^-52。eps 函数也可以接受一个浮点值作为参数,然后给出这个值与下一个可表示的浮点数值之间的绝对差。也就是说,eps(x) 产生一个和 x 类型相同的值,并且 x + eps(x) 恰好是比 x 更大的下一个可表示的浮点值:
实例
2.220446049250313e-16
julia> eps(1000.)
1.1368683772161603e-13
julia> eps(1e-27)
1.793662034335766e-43
julia> eps(0.0)
5.0e-324
两个相邻可表示的浮点数之间的距离并不是常数,数值越小,间距越小,数值越大,间距越大。换句话说,可表示的浮点数在实数轴上的零点附近最稠密,并沿着远离零点的方向以指数型的速度变得越来越稀疏。根据定义,eps(1.0) 与 eps(Float64) 相等,因为 1.0 是个 64 位浮点值。
Julia 也提供了 nextfloat 和 prevfloat 两个函数分别返回基于参数的下一个更大或更小的可表示的浮点数:
实例
1.25f0
julia> nextfloat(x)
1.2500001f0
julia> prevfloat(x)
1.2499999f0
julia> bitstring(prevfloat(x))
"00111111100111111111111111111111"
julia> bitstring(x)
"00111111101000000000000000000000"
julia> bitstring(nextfloat(x))
"00111111101000000000000000000001"
这个例子体现了一般原则,即相邻可表示的浮点数也有着相邻的二进制整数表示。
舍入模式
一个数如果没有精确的浮点表示,就必须被舍入到一个合适的可表示的值。
Julia 所使用的默认模式总是 RoundNearest,指舍入到最接近的可表示的值,这个被舍入的值会使用尽量少的有效位数。
实例
1.5
julia> BigFloat("1.550564889",2,RoundNearest)
1.5
julia> BigFloat("1.560564889",2,RoundNearest)
1.5
0 和 1 的字面量
Julia 提供了 0 和 1 的字面量函数,可以返回特定类型或所给变量的类型。
函数 | 描述 |
---|---|
zero(x) | x 类型或变量 x 的类型的零字面量 |
one(x) | x 类型或变量 x 的类型的一字面量 |
这些函数在数值比较中可以用来避免不必要的类型转换带来的开销。
例如:
实例
0.0f0
julia> zero(1.0)
0.0
julia> one(Int32)
1
julia> one(BigFloat)
1.0
类型转换
类型转换是把变量从一种类型转换为另一种数据类型。例如,如果您想存储一个 float 类型的值到一个简单的整型中,您需要把 float 类型强制转换为 int 类型。您可以使用强制类型转换运算符来把值显式地从一种类型转换为另一种类型,如下所示:
Julia 支持三种数值转换,它们在处理不精确转换上有所不同。第一种:
T(x) 或 convert(T,x)
以上都会把 x 转换为 T 类型。
- 如果 T 是浮点类型,转换的结果就是最近的可表示值, 可能会是正负无穷大。
- 如果 T 为整数类型,当 x 不能由 T 类型表示时,会抛出 InexactError。
第二种:
x % T 也可以将整数 x 转换为整型 T,与 x 模 2^n 的结果一致,其中 n 是 T 的位数。
第三种:
舍入函数接收一个 T 类型的可选参数。比如,round(Int,x) 是 Int(round(x)) 的简写版。
实例
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:
[...]