#parameters #julia #type-inference #arbitrary-precision
Вопрос:
Проблема возникла, когда я работал с Mods.jl. Этот пакет не поддерживает арифметику произвольной точности, поскольку в качестве параметров могут передаваться только примитивные типы, т.Е. Mod{17}
Работает нормально, но Mod{big"17"}
нет.
В связи с этим я решил реализовать что-то вроде BigMod
с двумя BigInt
полями
struct BigMod <: AbstractMod
value::BigInt
modulus::BigInt
end
Затем мне пришлось решить систему линейных сравнений, и, хотя она работала довольно хорошо Mod{N}
( A b
с некоторой дополнительной магией), она вообще не работала BigMod
.
Причина заключалась в том, что LinearAlgebra
пакет использует oneunit
функцию для вывода типов, но нет способа определить oneunit(::Type{BigMod})
, потому что мы не знаем модуль в этом случае (но мы знаем это для Mod{N}
). Однако эта функция может быть определена для переменной типа BigMod
, т.е. oneunit(x::BigMod)
.
Эта проблема может быть решена с помощью Base.return_types
inside of LinearAlgebra
для вывода типа, однако она кажется нестабильной по типу, а также возвращает набор возможных возвращаемых типов.
Я вижу только три способа решить эту проблему:
- В один прекрасный день можно было бы использовать любые (по крайней мере, неизменяемые) типы в параметрах. В этом случае дополнительный код не требуется, оригинал должен быть достаточно общим, чтобы все работало хорошо.
- В один прекрасный день вывод типов будет улучшен настолько, что не нужны подобные клуджи
typeof(oneunit(eltype(B)) / oneunit(eltype(F)))
, можно просто сказатьreturn_type(/, eltype.((B,F)))
, что является гораздо более общим. - Боритесь с болью и перепишите все необходимые вещи из
LinearAlgebra
специально дляBigMod
Существуют ли какие-либо другие способы достижения цели и какой способ является лучшим?
Комментарии:
1. Если вы в конечном итоге переписываете материал, я бы посоветовал сохранять значения в полях вместо параметров типа, как
BigMod
вы опубликовали.Mod{N}
Подход в Mods.jl работал нормально, потомуInt64
что был разрешен и более чем достаточно велик для большинства случаев. Ждать, пока основной язык разрешит больше вещей в качестве параметров типа, нецелесообразно. В какой-то момент он был расширен с onlyInt
иBool
до типов isbits, поэтому, должно быть, была какая-то неразрешимая причина, по которой они не расширили его дальше.
Ответ №1:
Параметрические типы могут содержать только isbits
или Symbol
. Следовательно, вы могли бы использовать очень простой в реализации, но чрезвычайно грязный и неэффективный обходной путь.
struct MyBigMod{S} <: AbstractMod
value::BigInt
end
Base.oneunit(::MyBigMod{S}) where S = parse(BigInt, string(S))
И теперь вы могли бы использовать его как:
julia> oneunit(MyBigMod{Symbol("55555555555555555555555")}(big"222222"))
55555555555555555555555
Может быть , ваши большие доходы в конце концов не такие уж и большие, и вы могли бы подумать ? using BitIntegers
Чем вы могли бы сделать что-то вроде:
julia> MyBigMod{int1024"55555555555555555555555"}
MyBigMod{55555555555555555555555}
Комментарии:
1. Не знал, что
BitIntegers
ваш ответ все прояснил. Спасибо!!!