Revision 48955b4fb190b8aa15aded80ce959097392cf44c authored by Shuhei Kadowaki on 11 May 2023, 10:21:50 UTC, committed by Jameson Nash on 20 May 2023, 01:28:18 UTC
1 parent a9e317b
Furlongs.jl
# This file is a part of Julia. License is MIT: https://julialang.org/license
module Furlongs
export Furlong
# Here we implement a minimal dimensionful type Furlong, which is used
# to test dimensional correctness of various functions in Base.
# represents a quantity in furlongs^p
struct Furlong{p,T<:Number} <: Number
val::T
Furlong{p,T}(v::Number) where {p,T} = new(v)
end
Furlong(x::T) where {T<:Number} = Furlong{1,T}(x)
Furlong(x::Furlong) = x
(::Type{T})(x::Furlong{0}) where {T<:Number} = T(x.val)::T
(::Type{T})(x::Furlong{0}) where {T<:Furlong{0}} = T(x.val)::T
(::Type{T})(x::Furlong{0}) where {T<:Furlong} = typeassert(x, T)
Furlong{p}(v::Number) where {p} = Furlong{p,typeof(v)}(v)
Furlong{p}(x::Furlong{q}) where {p,q} = (typeassert(x, Furlong{p}); Furlong{p,typeof(x.val)}(x.val))
Furlong{p,T}(x::Furlong{q}) where {T,p,q} = (typeassert(x, Furlong{p}); Furlong{p,T}(T(x.val)))
Base.promote_rule(::Type{Furlong{p,T}}, ::Type{Furlong{p,S}}) where {p,T,S} =
Furlong{p,promote_type(T,S)}
Base.promote_rule(::Type{Furlong{0,T}}, ::Type{S}) where {T,S<:Union{Real,Complex}} =
Furlong{0,promote_type(T,S)}
# only Furlong{0} forms a ring and isa Number
Base.convert(::Type{T}, y::Number) where {T<:Furlong{0}} = T(y)::T
Base.convert(::Type{Furlong}, y::Number) = Furlong{0}(y)
Base.convert(::Type{Furlong{<:Any,T}}, y::Number) where {T<:Number} = Furlong{0,T}(y)
Base.convert(::Type{T}, y::Number) where {T<:Furlong} = typeassert(y, T) # throws, since cannot convert a Furlong{0} to a Furlong{p}
# other Furlong{p} form a group
Base.convert(::Type{T}, y::Furlong) where {T<:Furlong{0}} = T(y)::T
Base.convert(::Type{Furlong}, y::Furlong) = y
Base.convert(::Type{Furlong{<:Any,T}}, y::Furlong{p}) where {p,T<:Number} = Furlong{p,T}(y)
Base.convert(::Type{T}, y::Furlong) where {T<:Furlong} = T(y)::T
Base.one(::Furlong{p,T}) where {p,T} = one(T)
Base.one(::Type{Furlong{p,T}}) where {p,T} = one(T)
Base.oneunit(::Furlong{p,T}) where {p,T} = Furlong{p,T}(one(T))
Base.oneunit(::Type{Furlong{p,T}}) where {p,T} = Furlong{p,T}(one(T))
Base.zero(::Furlong{p,T}) where {p,T} = Furlong{p,T}(zero(T))
Base.zero(::Type{Furlong{p,T}}) where {p,T} = Furlong{p,T}(zero(T))
Base.iszero(x::Furlong) = iszero(x.val)
Base.float(x::Furlong{p}) where {p} = Furlong{p}(float(x.val))
Base.eps(::Type{Furlong{p,T}}) where {p,T<:AbstractFloat} = Furlong{p}(eps(T))
Base.eps(::Furlong{p,T}) where {p,T<:AbstractFloat} = eps(Furlong{p,T})
Base.floatmin(::Type{Furlong{p,T}}) where {p,T<:AbstractFloat} = Furlong{p}(floatmin(T))
Base.floatmin(::Furlong{p,T}) where {p,T<:AbstractFloat} = floatmin(Furlong{p,T})
Base.floatmax(::Type{Furlong{p,T}}) where {p,T<:AbstractFloat} = Furlong{p}(floatmax(T))
Base.floatmax(::Furlong{p,T}) where {p,T<:AbstractFloat} = floatmax(Furlong{p,T})
Base.conj(x::Furlong{p,T}) where {p,T} = Furlong{p,T}(conj(x.val))
# convert Furlong exponent p to a canonical form
canonical_p(p) = isinteger(p) ? Int(p) : Rational{Int}(p)
Base.abs(x::Furlong{p}) where {p} = Furlong{p}(abs(x.val))
Base.abs2(x::Furlong{p}) where {p} = Furlong{canonical_p(2p)}(abs2(x.val))
Base.inv(x::Furlong{p}) where {p} = Furlong{canonical_p(-p)}(inv(x.val))
for f in (:isfinite, :isnan, :isreal, :isinf)
@eval Base.$f(x::Furlong) = $f(x.val)
end
for f in (:real,:imag,:complex,:+,:-)
@eval Base.$f(x::Furlong{p}) where {p} = Furlong{p}($f(x.val))
end
import Base: +, -, ==, !=, <, <=, isless, isequal, *, /, //, div, rem, mod, ^
for op in (:+, :-)
@eval function $op(x::Furlong{p}, y::Furlong{p}) where {p}
v = $op(x.val, y.val)
Furlong{p}(v)
end
end
for op in (:(==), :(!=), :<, :<=, :isless, :isequal)
@eval $op(x::Furlong{p}, y::Furlong{p}) where {p} = $op(x.val, y.val)::Bool
end
for (f,op) in ((:_plus,:+),(:_minus,:-),(:_times,:*),(:_div,://))
@eval function $f(v::T, ::Furlong{p}, ::Union{Furlong{q},Val{q}}) where {T,p,q}
s = $op(p, q)
Furlong{canonical_p(s),T}(v)
end
end
for (op,eop) in ((:*, :_plus), (:/, :_minus), (://, :_minus), (:div, :_minus))
@eval begin
$op(x::Furlong{p}, y::Furlong{q}) where {p,q} =
$eop($op(x.val, y.val),x,y)
$op(x::Furlong{p}, y::S) where {p,S<:Number} = $op(x,Furlong{0,S}(y))
$op(x::S, y::Furlong{p}) where {p,S<:Number} = $op(Furlong{0,S}(x),y)
end
end
# to fix an ambiguity
//(x::Furlong, y::Complex) = x // Furlong{0,typeof(y)}(y)
for op in (:rem, :mod)
@eval begin
$op(x::Furlong{p}, y::Furlong) where {p} = Furlong{p}($op(x.val, y.val))
$op(x::Furlong{p}, y::Number) where {p} = Furlong{p}($op(x.val, y))
end
end
Base.sqrt(x::Furlong) = _div(sqrt(x.val), x, Val(2))
end
Computing file changes ...