k = ModInt{7}(3)
1*k # works
1/k # ... fails with:
LoadError: MethodError: Cannot `convert` an object of type ModInt{7}
to an object of type AbstractFloat
This may have arisen from a call to the constructor AbstractFloat(...),
since type constructors fall back to convert methods.
while loading In[4], in expression starting on line 1
in /(::Int64, ::ModInt{7}) at ./int.jl:35
I can’t see why it successfully handles 1 * k but fails with 1 / k. There is a promotion_rule in place! How can it possibly succeed in one case and fail in the other?
PS Other tests:
A = ModInt{7}[1 2; 3 4]
A^2
B = rand(ModInt{7}, 3, 3)
B * inv(B)
There is a method defined for / where both types are a subtype of Integer. Both 1 and k are of types that subtype Integer and no more specific method exists, hence the method I linked is the one that will be executed.
Julia does not do implicit conversions. You need to add your own explicit method,/(a::Int, b::ModInt) = /(promote(a,b)...) or something like that.
Well, inv calls the generic fallback for lu factorization, which does pivoting by default, which in turn requires comparison of elements via < (actually, via > in lu.jl:36, but that falls back on <). The code should therefore work if you define <{n}(a::ModInt{n}, b::ModInt{n}).
Thanks! I can see why that might give rise to an inconsistent failure – it is a random matrix, so it is probably choosing a different pivot point each time.
Now for the tricky part: what on earth is a < operator going to do using clock arithmetic!
Is p-1 < 0? They are right next to one another, and p-1 is to the left of 0 just as 0 is to the left of 1.
^ strangely constructor (B) is required.
Which means that promote acting on (a::Integer , b::ModInt{n}) is having to ‘promote’ ModInt{n} -> ModInt{n} which looks inefficient.
Why not just use the original value? (it seems that Julia is performing a needless object copy)
Also it doesn’t quite seem aesthetically right that I need that Base.convert line. Shouldn’t Julia be able to infer from the fact that ModInt{n} has a constructor that takes an Int?
I wonder if we should add that fallback to Base. It would probably produce less confusing behavior in just such cases – i.e. a definition is provided for dividing a type by itself.
Fixed. This ended up being trickier than expected because of needing to avoid performance regressions for built-in types but in the end various division operations involving BigInts actually ended up getting faster. Sorry to have snagged the issue, @pitao – I wanted to get it fixed in time for 0.6.