May 14, 2021 Julia
1. Type conversion and type promotion
3. Define a new type conversion
4. Case: Score type conversion
Julia can promote parameters of mathematical operators to the same type, which have been mentioned in integers and floats, mathematical operations and basic functions, types, and methods.
In a sense, Julia is "non-automatic type promotion": mathematical operators are functions with special syntax, and the parameters of functions are not automatically converted. However, with overloading, you can still do the "automatic" type promotion.
convert
function is used to convert values to various types.
It has two parameters: the first is a type object, the second is a value to convert, and the return value is a value converted to a specified type:
julia> x = 12
12
julia> typeof(x)
Int64
julia> convert(Uint8, x)
0x0c
julia> typeof(ans)
Uint8
julia> convert(FloatingPoint, x)
12.0
julia> typeof(ans)
Float64
When a conversion cannot be encountered,
convert
throws a "no method" error:
julia> convert(FloatingPoint, "foo")
ERROR: `convert` has no method matching convert(::Type{FloatingPoint}, ::ASCIIString)
in convert at base.jl:13
Julia does not do type conversion between strings and numbers.
To define a new type conversion, simply
convert
new method for the convert. T
he following example converts a value to a Boolean value:
convert(::Type{Bool}, x::Number) = (x!=0)
The type of the first argument for this method
is a single-state
Bool
Type{Bool}
T
his method is called only if the
Bool
Bool. N
ote the syntax used by the first argument: the name of the argument is omitted before
::
and only the type of argument is given.
This is a function argument in Julia, and if its type is specified but the value of that parameter has never been used in the function body, the syntax is used, and in this case, because the argument is a monomorphic type, there is never any reason to use its value in the function body.
Check if the value is 0 when converting:
julia> convert(Bool, 1)
true
julia> convert(Bool, 0)
false
julia> convert(Bool, 1im)
ERROR: InexactError()
in convert at complex.jl:18
julia> convert(Bool, 0im)
false
The type conversions that are actually used are complex, and the following example is an implementation in Julia:
convert{T<:Real}(::Type{T}, z::Complex) = (imag(z)==0 ? convert(T,real(z)) :
throw(InexactError()))
julia> convert(Bool, 1im)
InexactError()
in convert at complex.jl:40
Continuing
Rational
case study, the declaration of type conversion in
rational.jl
follows the type declaration and constructor:
convert{T<:Integer}(::Type{Rational{T}}, x::Rational) = Rational(convert(T,x.num),convert(T,x.den))
convert{T<:Integer}(::Type{Rational{T}}, x::Integer) = Rational(convert(T,x), convert(T,1))
function convert{T<:Integer}(::Type{Rational{T}}, x::FloatingPoint, tol::Real)
if isnan(x); return zero(T)//zero(T); end
if isinf(x); return sign(x)//zero(T); end
y = x
a = d = one(T)
b = c = zero(T)
while true
f = convert(T,round(y)); y -= f
a, b, c, d = f*a+c, f*b+d, a, b
if y == 0 || abs(a/b-x) <= tol
return a//b
end
y = 1/y
end
end
convert{T<:Integer}(rt::Type{Rational{T}}, x::FloatingPoint) = convert(rt,x,eps(x))
convert{T<:FloatingPoint}(::Type{T}, x::Rational) = convert(T,x.num)/convert(T,x.den)
convert{T<:Integer}(::Type{T}, x::Rational) = div(convert(T,x.num),convert(T,x.den))
The first four definitions ensure
a//b == convert(Rational{Int64}, a/b)
The last two convert fractions to floating-point and integer types.
Type promotion refers to converting various types of values to the same type.
It has nothing to do with type hierarchy, for
Int32
can be
Float64
Int32
is
Float64
Julia uses
promote
function for type promotion, which can have as many arguments as any number, and it returns the same type of plural group of the same number;
Type promotion is often used to convert numeric parameters to the same type:
julia> promote(1, 2.5)
(1.0,2.5)
julia> promote(1, 2.5, 3)
(1.0,2.5,3.0)
julia> promote(2, 3//4)
(2//1,3//4)
julia> promote(1, 2.5, 3, 3//4)
(1.0,2.5,3.0,0.75)
julia> promote(1.5, im)
(1.5 + 0.0im,0.0 + 1.0im)
julia> promote(1 + 2im, 3//4)
(1//1 + 2//1*im,3//4 + 0//1*im)
The floating-point value is promoted to the highest floating-point type. T he integer value is raised to the native word length or highest integer value type of the local machine. W hen there are both integers and floats, they are promoted to floating-point types that can include all values. W hen there is both an integer and a score, it is promoted to a score. W hen there are both scores and floats, they are promoted to floats. When both complex and real, it is promoted to an appropriate complex number.
In numerical operations, mathematical
*
+
-
of , -
/
, are "smartly" applied to type promotion. T
he following example
is some of the definitions in promotion.jl:
+(x::Number, y::Number) = +(promote(x,y)...)
-(x::Number, y::Number) = -(promote(x,y)...)
*(x::Number, y::Number) = *(promote(x,y)...)
/(x::Number, y::Number) = /(promote(x,y)...)
Other methods of arithmetic and mathematical operation type promotion are also defined in
promotion.jl,
but promote is rarely called in the Julia standard
promote
promote
generally used in external construction methods to adapt constructors to different types of parameters.
The following external construction methods
are available in rational.jl:
Rational(n::Integer, d::Integer) = Rational(promote(n,d)...)
Examples of this method:
julia> Rational(int8(15),int32(-5))
-3//1
julia> typeof(ans)
Rational{Int64} (constructor with 1 method)
For custom types, it is best for the programmer to explicitly provide the constructor with the type it expects. However, when dealing with numerical problems, it is convenient to do automatic type promotion.
Although you can define
promote
for the promote function, this is too cumbersome. W
e use the auxiliary
promote_rule
define the behavior of
promote
promote.
promote_rule
receives type object pairs and returns another type object.
This function elevates the instance of the type in the argument to the type to return:
promote_rule(::Type{Float64}, ::Type{Float32} ) = Float64
The promoted type does not need to be the same as the argument type of the function. H ere's an example from the Julia Standard Library:
promote_rule(::Type{Uint8}, ::Type{Int8}) = Int
promote_rule(::Type{Char}, ::Type{Uint8}) = Int32
promote_rule(::Type{A}, ::Type{B})
promote_rule(::Type{B}, ::Type{A})
promote_rule
implies symmetry during promotion.
promote_type
is
promote_rule
function, which receives any number of type objects and
promote
when they are the promote parameter.
You can
promote_type
to see what type of combination a particular type is promoted to:
julia> promote_type(Int8, Uint16)
Int64
promote
uses
promote_type
determine which type to convert parameter values to when a type is promoted.
The full type promotion mechanism is
visible at promotion.jl,
with a total of 35 lines.
Let's close the Julia score type case:
promote_rule{T<:Integer}(::Type{Rational{T}}, ::Type{T}) = Rational{T}
promote_rule{T<:Integer,S<:Integer}(::Type{Rational{T}}, ::Type{S}) = Rational{promote_type(T,S)}
promote_rule{T<:Integer,S<:Integer}(::Type{Rational{T}}, ::Type{Rational{S}}) = Rational{promote_type(T,S)}
promote_rule{T<:Integer,S<:FloatingPoint}(::Type{Rational{T}}, ::Type{S}) = promote_type(T,S)