Julia Data Types
In programming languages, there are basic mathematical operations and scientific calculations. Their commonly used data types areintegersandfloating-pointnumbers.In addition, there is also a"literal"term. A literal is a notation used to express a fixed value in source code. Integers, floating-point numbers, strings, etc. are all literals.
For example:
a=1 // a is a variable, 1 is an integer literal b=1.0 // b is a variable, 1.0 is a floating-point literalJulia provides a rich set of primitive numeric types, and defines a complete set of arithmetic operations based on them. In addition, it also provides bitwise operators and some standard mathematical functions.
Integer Types
The following table lists the integer types supported by Julia:
| Type | Signed? | Number of bits | Minimum value | Maximum value |
|---|---|---|---|---|
| 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) |
Integer literal forms:
Example
1
julia> 1234
1234
The default type of an integer literal depends on whether the target system is a 32-bit or 64-bit architecture (most systems today are 64-bit):
Example
julia> typeof(1)
Int32
# 64-bit system:
julia> typeof(1)
Int64
Julia's built-in variableSys.WORD_SIZEindicates whether the target system is a 32-bit or 64-bit architecture:
Example
julia> Sys.WORD_SIZE
32
# 64-bit system:
julia> Sys.WORD_SIZE
64
Julia also defines Int and UInt types, which are aliases for the system's signed and unsigned native integer types, respectively.
Example
julia> Int
Int32
julia> UInt
UInt32
# 64-bit system:
julia> Int
Int64
julia> UInt
UInt64
Overflow Behavior
In Julia, exceeding the maximum value representable by a type causes wraparound behavior:
Example
9223372036854775807
julia> x + 1
-9223372036854775808
julia> x + 1 == typemin(Int64)
true
Therefore, Julia's integer arithmetic is actually a form of modular arithmetic, reflecting the characteristics of how modern computers implement low-level arithmetic. In programs where overflow may occur, explicit checks for wraparound at the boundaries of the extreme values are necessary. Otherwise, the BigInt type from arbitrary-precision arithmetic is recommended as an alternative.
Below is an example of overflow behavior and how to solve overflow:
Example
-8446744073709551616
julia> big(10)^19
10000000000000000000
Division Errors
Integer division triggers a DivideError in the following two exceptional cases:- Division by zero
- Division by the smallest negative number
remThe remainder function andmodthe modulus function throw a DivideError when dividing by zero. Here is an example:
Example
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
Floating-Point Types
The following table lists the floating-point types supported by Julia:
| Type | Precision | Number of bits |
|---|---|---|
| Float16 | Half precision | 16 |
| Float32 | Single precision | 32 |
| Float64 | Double precision | 64 |
In addition, full support for complex and rational numbers is built on top of these primitive data types.
The format of floating-point literals is shown below. When necessary, you can useEto express it.
Example
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
Note:
In scientific notation, to simplify formulas, the format withEcan be used for representation. For example, 1.03 times 10 to the 8th power can be abbreviated as "1.03E+08", where "E" is the abbreviation of exponent.
The results above are all Float64 values. Using f instead of e yields Float32 literals:
Example
0.5f0
julia> typeof(x)
Float32
julia> 2.5f-4
0.00025f0
Numbers can be easily converted toFloat32type:
julia> x = Float32(-1.5)
-1.5f0
julia> typeof(x)
Float32
There are also hexadecimal floating-point literals, but they only apply to values of the Float64 type. They are generally represented using the p prefix and an exponent with base 2:
Example
1.0
julia> 0x1.8p3
12.0
julia> x = 0x.4p-1
0.125
julia> typeof(x)
Float64
Julia also supports half-precision floating-point numbers (Float16), but they areFloat32implemented through software emulation.
julia> sizeof(Float16(4.))
2
julia> 2*Float16(4.)
Float16(8.0)
Underscore_can be used as a digit separator:
Example
(10000, 5.0e-9, 0xdeadbeef, 0xb2)
Zero in Floating-Point Numbers
Floating-point numbers have two kinds of zeros: positive zero and negative zero. They are equal to each other but have different binary representations, which can be viewed using the bitstring function:
Example
true
julia> bitstring(0.0)
"0000000000000000000000000000000000000000000000000000000000000000"
julia> bitstring(-0.0)
"1000000000000000000000000000000000000000000000000000000000000000"
Special Floating-Point Values
There are three specific standard floating-point values that do not correspond to any point on the real number line:
| Float16 | Float32 | Float64 | Name | Description |
|---|---|---|---|---|
| Inf16 | Inf32 | Inf | Positive infinity | A number greater than all finite floating-point numbers |
| -Inf16 | -Inf32 | -Inf | Negative infinity | A number less than all finite floating-point numbers |
| NaN16 | NaN32 | NaN | Not a number | A value that is not equal (==) to any floating-point value (including itself) |
The following lists some examples of operations on floating-point numbers:
Example
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
We can also use the typemin and typemax functions:
Example
(-Inf16, Inf16)
julia> (typemin(Float32),typemax(Float32))
(-Inf32, Inf32)
julia> (typemin(Float64),typemax(Float64))
(-Inf, Inf)
Machine Precision
Most real numbers cannot be represented exactly by floating-point numbers, so it is necessary to know the distance between two adjacent representable floating-point numbers, which is usually called machine precision.
Julia provides theepsfunction, which gives the difference between 1.0 and the next floating-point number that Julia can represent:
Example
1.1920929f-7
julia> eps(Float64)
2.220446049250313e-16
julia> eps() # Same as eps(Float64)
2.220446049250313e-16
These values are 2.0^-23 in Float32 and 2.0^-52 in Float64, respectively. The eps function can also take a floating-point value as an argument and return the absolute difference between this value and the next representable floating-point value. That is, eps(x) yields a value of the same type as x, and x + eps(x) is exactly the next representable floating-point value greater than x:
Example
2.220446049250313e-16
julia> eps(1000.)
1.1368683772161603e-13
julia> eps(1e-27)
1.793662034335766e-43
julia> eps(0.0)
5.0e-324
The distance between two adjacent representable floating-point numbers is not constant: the smaller the number, the smaller the gap; the larger the number, the larger the gap. In other words, representable floating-point numbers are densest near zero on the real number line, and become increasingly sparse exponentially as they move away from zero. By definition, eps(1.0) is equal to eps(Float64), because 1.0 is a 64-bit floating-point value.
Julia also provides two functions, nextfloat and prevfloat, which return the next greater or smaller representable floating-point number based on the argument, respectively:
Example
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"
This example illustrates the general principle that adjacent representable floating-point numbers also have adjacent binary integer representations.
Rounding Modes
If a number does not have an exact floating-point representation, it must be rounded to a suitable representable value.
The default mode used by Julia is alwaysRoundNearest, which means rounding to the nearest representable value, and the rounded value uses as few significant digits as possible.
Example
1.5
julia> BigFloat("1.550564889",2,RoundNearest)
1.5
julia> BigFloat("1.560564889",2,RoundNearest)
1.5
Zero and One Literals
Julia provides literal functions for 0 and 1, which can return the literal of a specific type or the type of a given variable.
| Function | Description |
|---|---|
| zero(x) | Zero literal of type x or of the type of variable x |
| one(x) | One literal of type x or of the type of variable x |
These functions can be used in numerical comparisons to avoid the overhead of unnecessary type conversions.
For example:
Example
0.0f0
julia> zero(1.0)
0.0
julia> one(Int32)
1
julia> one(BigFloat)
1.0
Type Conversion
Type conversion is the process of converting a variable from one type to another data type. For example, if you want to store a float value in a simple integer, you need to cast the float type to an int type. You can use the cast operator to explicitly convert a value from one type to another, as shown below:
Julia supports three kinds of numeric conversion, which differ in how they handle inexact conversions.The first kind:
T(x) 或 convert(T,x)
All of the above convert x to type T.
- If T is a floating-point type, the result is the nearest representable value, which may be positive or negative infinity.
- If T is an integer type, an InexactError is thrown when x cannot be represented by type T.
The second kind:
x % TIt is also possible to convert an integer x to an integer type T, consistent with the result of x modulo 2^n, where n is the number of bits in T.
The third kind:
The rounding functions take an optional argument of type T. For example, round(Int,x) isInt(round(x))the abbreviated form.
Example
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:
[...]