Julia's built-in numeric types include a wide range of
π
typeof(π)
Float64(π)
pi = BigFloat(π)
exp(pi*1im)
exp(π*1im)
typeof(ans)
Rational(Float32(pi))
@show Float32(13176795/4194304);
@show Float32(pi);
5.0 + 3im
typeof(ans)
5//3 + 7//9im
typeof(ans)
subtypes(Number)
subtypes(Real)
subtypes(AbstractFloat)
Int32 <: Number # are Int64's numbers?
Int64 <: Real # are Int64's a subset of the reals?
Int64 <: Float64 # are Int64's a subset of 64-bit floating-point numbers?
17 ∈ 0:3:21 # is 17 an element of the set 0,3,6,9,12,15,18,21? (a set operation)
typeof(ans)
illustrates linear algebra over arbitrary-precision rationals
A = convert(Matrix{Rational{BigInt}}, rand(1:10,5,5))/10
x = [3//4; 17//3; -1//13; -7//11 ; 3//19]
b = A*x
x̂ = A\b
x - x̂
Note that Julia's backslash operator (and LU decomp) works over all its numeric types
Float32 and Float64 LU, QR, SVD, etc. are calls to LAPACK
example from Andreas Noack, CSAIL MIT http://andreasnoack.github.io/talks/2015AprilStanford_AndreasNoack.ipynb
# Scalar finite fields. P is the modulus, T is the integer type (Int16, Int32, ...)
immutable GF{P,T<:Integer} <: Number
data::T
function GF(x::Integer)
return new(mod(x, P))
end
end
immutable: In Julia variables change values, but numbers do not.
# basic methods for scalar finite field
import Base: convert, inv, one, promote_rule, show, zero
function call{P}(::Type{GF{P}}, x::Integer)
if !isprime(P)
throw(ArgumentError("P must be a prime"))
end
return GF{P,typeof(x)}(mod(x, P))
end
convert{P,T}(::Type{GF{P,T}}, x::Integer) = GF{P}(x)
convert{P}(::Type{GF{P}}, x::Integer) = GF{P}(x)
convert{P,T}(::Type{GF{P,T}}, x::GF{P}) = GF{P,T}(x.data)
promote_rule{P,T1,T2<:Integer}(::Type{GF{P,T1}}, ::Type{T2}) = GF{P,promote_type(T1,T2
)}
show(io::IO, x::GF) = show(io, x.data)
import Base: +, -, *, /
for op in (:+, :-, :*)
@eval begin
($op){P,T}(x::GF{P,T}, y::GF{P,T}) = GF{P,T}($(op)(x.data, y.data))
end
end
x, y = GF{5}(9), GF{5}(8)
@show x
@show y
@show x + y
@show x - y
@show x * y
;
# Division requires slightly more care
function inv{P,T}(x::GF{P,T})
if x == zero(x)
throw(DivideError())
end
r, u, v = gcdx(x.data, P)
GF{P,T}(u)
end
(/){P}(x::GF{P}, y::GF{P}) = x*inv(y)
;
@show x / y
@show x \ y # backslash on any Number is defined in terms of /, so we get it autmomatically
;
# create 4x4 matrix of random GF(5) elems
srand(1234)
A = [GF{5}(rand(0:4)) for i = 1:4, j = 1:4]
b = [GF{5}(rand(0:4)) for i = 1:4]
x = A\b
A*x - b
typeof(x)
methods(+)
@which x + y
@which GF{7}(4) + GF{7}(1)
@which 4+8
matrix-matrix mult
A1, A2 = rand(1:100, 100, 100), rand(1:100, 100, 100)
A1*A2 # warm up to be sure function is compiled
print("int mat mult ")
@time A1*A2
AF1, AF2 = map(GF{5}, A1), map(GF{5}, A2)
AF1*AF2
print("GF(p) mat mult ")
@time AF1*AF2
;
LU factorization: Float64 via LAPACK, GF(p) via generic LU algorithm
lufact(A1)
print("Float64 mat lufact ")
@time lufact(A1) # Promoted to Float64 and calls LAPACK
F = lufact(AF1,Val{false})
while F.info != 0
AF1[F.info, F.info] += 1
F = lufact(AF1, Val{false})
end
lufact(AF1)
print("GF(p) mat lufact ")
@time lufact(AF1) # Non-blocked generic LU implemented in Julia
;