|
| 1 | +# This file is a part of Julia. License is MIT: https://julialang.org/license |
| 2 | + |
| 3 | +module Furlongs |
| 4 | + |
| 5 | +export Furlong |
| 6 | + |
| 7 | +# Here we implement a minimal dimensionful type Furlong, which is used |
| 8 | +# to test dimensional correctness of various functions in Base. |
| 9 | + |
| 10 | +# represents a quantity in furlongs^p |
| 11 | +struct Furlong{p,T<:Number} <: Number |
| 12 | + val::T |
| 13 | + Furlong{p,T}(v::Number) where {p,T} = new(v) |
| 14 | +end |
| 15 | +Furlong(x::T) where {T<:Number} = Furlong{1,T}(x) |
| 16 | +Furlong(x::Furlong) = x |
| 17 | +(::Type{T})(x::Furlong{0}) where {T<:Number} = T(x.val)::T |
| 18 | +(::Type{T})(x::Furlong{0}) where {T<:Furlong{0}} = T(x.val)::T |
| 19 | +(::Type{T})(x::Furlong{0}) where {T<:Furlong} = typeassert(x, T) |
| 20 | +Furlong{p}(v::Number) where {p} = Furlong{p,typeof(v)}(v) |
| 21 | +Furlong{p}(x::Furlong{q}) where {p,q} = (typeassert(x, Furlong{p}); Furlong{p,typeof(x.val)}(x.val)) |
| 22 | +Furlong{p,T}(x::Furlong{q}) where {T,p,q} = (typeassert(x, Furlong{p}); Furlong{p,T}(T(x.val))) |
| 23 | + |
| 24 | +Base.promote_rule(::Type{Furlong{p,T}}, ::Type{Furlong{p,S}}) where {p,T,S} = |
| 25 | + Furlong{p,promote_type(T,S)} |
| 26 | +Base.promote_rule(::Type{Furlong{0,T}}, ::Type{S}) where {T,S<:Union{Real,Complex}} = |
| 27 | + Furlong{0,promote_type(T,S)} |
| 28 | +# only Furlong{0} forms a ring and isa Number |
| 29 | +Base.convert(::Type{T}, y::Number) where {T<:Furlong{0}} = T(y)::T |
| 30 | +Base.convert(::Type{Furlong}, y::Number) = Furlong{0}(y) |
| 31 | +Base.convert(::Type{Furlong{<:Any,T}}, y::Number) where {T<:Number} = Furlong{0,T}(y) |
| 32 | +Base.convert(::Type{T}, y::Number) where {T<:Furlong} = typeassert(y, T) # throws, since cannot convert a Furlong{0} to a Furlong{p} |
| 33 | +# other Furlong{p} form a group |
| 34 | +Base.convert(::Type{T}, y::Furlong) where {T<:Furlong{0}} = T(y)::T |
| 35 | +Base.convert(::Type{Furlong}, y::Furlong) = y |
| 36 | +Base.convert(::Type{Furlong{<:Any,T}}, y::Furlong{p}) where {p,T<:Number} = Furlong{p,T}(y) |
| 37 | +Base.convert(::Type{T}, y::Furlong) where {T<:Furlong} = T(y)::T |
| 38 | + |
| 39 | +Base.one(::Furlong{p,T}) where {p,T} = one(T) |
| 40 | +Base.one(::Type{Furlong{p,T}}) where {p,T} = one(T) |
| 41 | +Base.oneunit(::Furlong{p,T}) where {p,T} = Furlong{p,T}(one(T)) |
| 42 | +Base.oneunit(::Type{Furlong{p,T}}) where {p,T} = Furlong{p,T}(one(T)) |
| 43 | +Base.zero(::Furlong{p,T}) where {p,T} = Furlong{p,T}(zero(T)) |
| 44 | +Base.zero(::Type{Furlong{p,T}}) where {p,T} = Furlong{p,T}(zero(T)) |
| 45 | +Base.iszero(x::Furlong) = iszero(x.val) |
| 46 | +Base.float(x::Furlong{p}) where {p} = Furlong{p}(float(x.val)) |
| 47 | +Base.eps(::Type{Furlong{p,T}}) where {p,T<:AbstractFloat} = Furlong{p}(eps(T)) |
| 48 | +Base.eps(::Furlong{p,T}) where {p,T<:AbstractFloat} = eps(Furlong{p,T}) |
| 49 | +Base.floatmin(::Type{Furlong{p,T}}) where {p,T<:AbstractFloat} = Furlong{p}(floatmin(T)) |
| 50 | +Base.floatmin(::Furlong{p,T}) where {p,T<:AbstractFloat} = floatmin(Furlong{p,T}) |
| 51 | +Base.floatmax(::Type{Furlong{p,T}}) where {p,T<:AbstractFloat} = Furlong{p}(floatmax(T)) |
| 52 | +Base.floatmax(::Furlong{p,T}) where {p,T<:AbstractFloat} = floatmax(Furlong{p,T}) |
| 53 | +Base.conj(x::Furlong{p,T}) where {p,T} = Furlong{p,T}(conj(x.val)) |
| 54 | + |
| 55 | +# convert Furlong exponent p to a canonical form |
| 56 | +canonical_p(p) = isinteger(p) ? Int(p) : Rational{Int}(p) |
| 57 | + |
| 58 | +Base.abs(x::Furlong{p}) where {p} = Furlong{p}(abs(x.val)) |
| 59 | +Base.abs2(x::Furlong{p}) where {p} = Furlong{canonical_p(2p)}(abs2(x.val)) |
| 60 | +Base.inv(x::Furlong{p}) where {p} = Furlong{canonical_p(-p)}(inv(x.val)) |
| 61 | + |
| 62 | +for f in (:isfinite, :isnan, :isreal, :isinf) |
| 63 | + @eval Base.$f(x::Furlong) = $f(x.val) |
| 64 | +end |
| 65 | +for f in (:real,:imag,:complex,:+,:-) |
| 66 | + @eval Base.$f(x::Furlong{p}) where {p} = Furlong{p}($f(x.val)) |
| 67 | +end |
| 68 | + |
| 69 | +import Base: +, -, ==, !=, <, <=, isless, isequal, *, /, //, div, rem, mod, ^ |
| 70 | +for op in (:+, :-) |
| 71 | + @eval function $op(x::Furlong{p}, y::Furlong{p}) where {p} |
| 72 | + v = $op(x.val, y.val) |
| 73 | + Furlong{p}(v) |
| 74 | + end |
| 75 | +end |
| 76 | +for op in (:(==), :(!=), :<, :<=, :isless, :isequal) |
| 77 | + @eval $op(x::Furlong{p}, y::Furlong{p}) where {p} = $op(x.val, y.val)::Bool |
| 78 | +end |
| 79 | +for (f,op) in ((:_plus,:+),(:_minus,:-),(:_times,:*),(:_div,://)) |
| 80 | + @eval function $f(v::T, ::Furlong{p}, ::Union{Furlong{q},Val{q}}) where {T,p,q} |
| 81 | + s = $op(p, q) |
| 82 | + Furlong{canonical_p(s),T}(v) |
| 83 | + end |
| 84 | +end |
| 85 | +for (op,eop) in ((:*, :_plus), (:/, :_minus), (://, :_minus), (:div, :_minus)) |
| 86 | + @eval begin |
| 87 | + $op(x::Furlong{p}, y::Furlong{q}) where {p,q} = |
| 88 | + $eop($op(x.val, y.val),x,y) |
| 89 | + $op(x::Furlong{p}, y::S) where {p,S<:Number} = $op(x,Furlong{0,S}(y)) |
| 90 | + $op(x::S, y::Furlong{p}) where {p,S<:Number} = $op(Furlong{0,S}(x),y) |
| 91 | + end |
| 92 | +end |
| 93 | +# to fix an ambiguity |
| 94 | +//(x::Furlong, y::Complex) = x // Furlong{0,typeof(y)}(y) |
| 95 | +for op in (:rem, :mod) |
| 96 | + @eval begin |
| 97 | + $op(x::Furlong{p}, y::Furlong) where {p} = Furlong{p}($op(x.val, y.val)) |
| 98 | + $op(x::Furlong{p}, y::Number) where {p} = Furlong{p}($op(x.val, y)) |
| 99 | + end |
| 100 | +end |
| 101 | +Base.sqrt(x::Furlong) = _div(sqrt(x.val), x, Val(2)) |
| 102 | +Base.muladd(x::Furlong, y::Furlong, z::Furlong) = x*y + z |
| 103 | +Base.muladd(x::Furlong, y::Number, z::Number) = x*y + z |
| 104 | +Base.muladd(x::Furlong, y::Furlong, z::Number) = x*y + z |
| 105 | +Base.muladd(x::Number, y::Furlong, z::Number) = x*y + z |
| 106 | +Base.muladd(x::Number, y::Number, z::Furlong) = x*y + z |
| 107 | +Base.muladd(x::Number, y::Furlong, z::Furlong) = x*y + z |
| 108 | +Base.muladd(x::Furlong, y::Number, z::Furlong) = x*y + z |
| 109 | + |
| 110 | +end |
0 commit comments