Сколько бит будет занимать 52-битное значение, если оно хранится как Integer
?
Это зависит от реализации. В GHC значения, которые помещаются внутри машинного слова, хранятся непосредственно в конструкторе Integer
, поэтому, если вы работаете на 64-битной машине, он должен занимать столько же места, что и Int. Это соответствует конструктору S#
из Integer
:
data Integer = S# Int#
| J# Int# ByteArray#
Большие значения (т. Е. Те, которые обозначены J#
) сохраняются с GMP .
Правильно ли, что Int64
и Word64
позволяют хранить 64-битные данные и весить ровно 64 бита для любого значения?
Не совсем - они в штучной упаковке . Int64
- это фактически указатель на неоцененный раздел или указатель из одного слова на информационную таблицу плюс 64-битное целочисленное значение. (См. Комментарий GHC для получения дополнительной информации.)
Если вы действительно хотите что-то, что гарантированно будет 64-битным, без исключений, тогда вы можете использовать распакованный тип, например Int64#
, но я настоятельно рекомендую сначала профилировать; распакованные значения довольно болезненно использовать. Например, вы не можете использовать распакованные типы в качестве аргументов для конструкторов типов, поэтому у вас не может быть списка Int64#
s. Вы также должны использовать операции, специфичные для целых чисел без коробки. И, конечно, все это исключительно для GHC.
Если вы хотите хранить много 52-битных целых чисел, вы можете использовать vector или repa (построенный на векторе, с такими причудливыми вещами, как автоматический параллелизм) ; они хранят распакованные значения под капотом, но позволяют работать с ними в штучной упаковке. (Конечно, каждое отдельное значение, которое вы вынимаете, будет в штучной упаковке.)
Являются ли какие-либо из этих типов более производительными или предпочтительными по каким-либо иным причинам, чем размер, например Реализация собственного кода или прямая оптимизация, связанная с инструкциями процессора?
Да; использование Integer
подразумевает ветвление для каждой операции, поскольку оно должно различать регистр машинного слова и bignum; и, конечно, он должен справляться с переполнением. Интегральные типы фиксированного размера позволяют избежать этих издержек.
И на всякий случай: какой из них вы бы порекомендовали для хранения 52-битного значения в приложении, чрезвычайно чувствительном с точки зрения производительности?
Если вы используете 64-битный компьютер: Int64
или, если необходимо, Int64#
.
Если вы используете 32-разрядный компьютер: вероятно, Integer
, поскольку 32-разрядный Int64
эмулируется вызовами FFI для функций GHC, которые, вероятно, не очень оптимизированы, но я бы попробовал и сравните это. С Integer
вы получите лучшую производительность для маленьких целых чисел, а GMP сильно оптимизирован, поэтому он, вероятно, будет лучше работать с большими, чем вы думаете.
Вы можете выбирать между Int64
и Integer
во время компиляции, используя препроцессор C (включается с {-# LANGUAGE CPP #-}
); Я думаю, что было бы легко заставить Cabal управлять #define
на основе ширины слова целевой архитектуры. Остерегайтесь, конечно, что они не одинаковы; Вы должны быть осторожны, чтобы избежать «переполнения» в коде Integer
, и, например, Int64
является экземпляром Bounded
, а Integer
- нет. Возможно, было бы проще всего просто ориентироваться на ширину одного слова (и, следовательно, на тип) для повышения производительности и жить с более низкой производительностью на другом.
Я бы предложил создать свой собственный тип Int52
в качестве оболочки newtype
поверх Int64
или оболочки Word52
поверх Word64
- просто выберите тот, который лучше соответствует вашим данным, не должно быть никакого влияния на производительность; если бы это были просто произвольные биты, я бы пошел с Int64
, просто потому, что Int
встречается чаще, чем Word
.
Вы можете определить все экземпляры для автоматической обработки переноса (попробуйте :info Int64
в GHCi, чтобы выяснить, какие экземпляры вы хотите определить) и предоставить «небезопасные» операции, которые просто применяются непосредственно под newtype
для повышения производительности. -критические ситуации, когда вы знаете, что переполнения не будет.
Затем, если вы не экспортируете конструктор newtype
, вы всегда можете поменять местами реализацию Int52
позже, не изменяя остальную часть вашего кода.Не беспокойтесь о накладных расходах отдельного типа - представление newtype
во время выполнения полностью идентично базовому типу;они существуют только во время компиляции.