I have a struct representing the remainders of an integer with respect to several moduli. All of the moduli fit into Int64 except for 2^64, so every modulus is either an Int64 or Type{Int64}.
struct LooseGoose{N}
remainders::NTuple{N,Int64}
moduli::NTuple{N,Union{DataType,Int64}}
end
import Base: *
*(g::LooseGoose, r::Int64) = LooseGoose( mod.( widen.(g.remainders) .* r , g.moduli) .|> Int64 , g.moduli )
LooseGoose((4,7,12),(Int64,11,17)) * 7
This works fine, except in practice I always want the first modulus to be Int64 and the remaining moduli to be numeric. Is there a convenient way to specify this in the type definition without the Union. I can enforce this in a constructor.
struct StrictGoose{N}
remainders::NTuple{N,Int64}
moduli::NTuple{N,Union{DataType,Int64}}
function StrictGoose(remainders::NTuple{N,Int64}, moduli) where {N}
moduli isa Tuple{DataType, (Int64 for i=2:N)...} || throw(ArguementError("moduli of incorrect form"))
new{N}(remainders,moduli)
end
end
StrictGoose((4,7,12),(Int64,11,17)) # Succeeds
StrictGoose((4,7,12),(13,Int64,17)) # Throws an error
- Is there a way to eliminate the
Unionand specifyTuple{DataType, (Int64 for i=2:N)...}more directly in the type definition? - If the type of
moduliis going to be restricted by the constructor anyway should I eliminate the annotation in the type declaration? - Would I be better off using
0as a sentinel value forInt64so myGoosecan beisbitstype, but then having to replacemodwith something that watches for this value?
modif(a,b) = b==0 ? a : mod(a,b)