parse fromintegral float convertir convert haskell integer

float - fromintegral haskell



`Integer` vs` Int64` vs `Word64` (1)

Tengo algunos datos que se pueden representar con un tipo Integral sin signo y su valor más grande requiere 52 bits. Solo AFAIK Integer , Int64 y Word64 satisfacen estos requisitos.

Toda la información que pude encontrar sobre esos tipos fue que Integer está firmado y tiene un tamaño de bit ilimitado flotante, Int64 y Word64 están fijos y firmados y sin firma respectivamente. Lo que no pude averiguar fue la información sobre la implementación real de esos tipos:

  1. ¿Cuántos bits ocupará realmente un valor de 52 bits si se almacena como un Integer ?

  2. ¿Estoy Int64 que Int64 y Word64 permiten almacenar datos de 64 bits y pesar exactamente 64 bits para cualquier valor?

  3. ¿Alguno de esos tipos es más eficaz o preferible por cualquier otro motivo que no sea el tamaño, por ejemplo, implementaciones de código nativo o optimizaciones relacionadas con las instrucciones del procesador directo?

  4. Y por si acaso: ¿cuál recomendaría para almacenar un valor de 52 bits en una aplicación extremadamente sensible en términos de rendimiento?


¿Cuántos bits ocupará realmente un valor de 52 bits si se almacena como un Integer ?

Esto depende de la implementación. Con GHC, los valores que caben dentro de una palabra de máquina se almacenan directamente en un constructor de Integer , por lo que si está en una máquina de 64 bits, debería ocupar la misma cantidad de espacio que un Int. Esto corresponde al constructor S# de Integer :

data Integer = S# Int# | J# Int# ByteArray#

Los valores más grandes (es decir, aquellos representados con J# ) se almacenan con GMP .

¿Estoy Int64 que Int64 y Word64 permiten almacenar datos de 64 bits y pesar exactamente 64 bits para cualquier valor?

No del todo, están en caja . Un Int64 es en realidad un puntero a un procesador no evaluado o un puntero de una palabra a una tabla de información más un valor entero de 64 bits. (Vea el comentario de GHC para más información.)

Si realmente desea algo que garantice que sea de 64 bits, sin excepciones, puede usar un tipo sin Int64# como Int64# , pero recomendaría encarecidamente la creación de perfiles; Los valores sin caja son muy dolorosos de usar. Por ejemplo, no puede usar tipos sin caja como argumentos para escribir constructores, por lo que no puede tener una lista de Int64# s. También tienes que usar operaciones específicas para enteros sin caja. Y, por supuesto, todo esto es extremadamente específico de GHC.

Si desea almacenar una gran cantidad de enteros de 52 bits, es posible que desee utilizar vector o repa (construido en vectores, con elementos sofisticados como el paralelismo automático); almacenan los valores sin caja debajo del capó, pero le permiten trabajar con ellos en forma de caja. (Por supuesto, cada valor individual que saque estará en caja).

¿Alguno de esos tipos es más eficaz o preferible por cualquier otro motivo que no sea el tamaño, por ejemplo, implementaciones de código nativo o optimizaciones relacionadas con las instrucciones del procesador directo?

Sí; el uso de Integer incurre en una rama para cada operación, ya que tiene que distinguir los casos de máquina-palabra y bignum; Y, por supuesto, tiene que manejar el desbordamiento. Los tipos integrales de tamaño fijo evitan esta sobrecarga.

Y por si acaso: ¿cuál recomendaría para almacenar un valor de 52 bits en una aplicación extremadamente sensible en términos de rendimiento?

Si está utilizando una máquina de 64 bits: Int64 o, si debe Int64# , Int64# .

Si está utilizando una máquina de 32 bits: Probablemente Integer , ya que en Int64 32 bits se emula con llamadas de FFI a funciones de GHC que probablemente no están muy optimizadas, pero probaría ambas y la compararía. Con Integer , obtendrá el mejor rendimiento en enteros pequeños, y GMP está fuertemente optimizado, por lo que probablemente se desempeñará mejor en los más grandes de lo que cree.

Puede seleccionar entre Int64 e Integer en tiempo de compilación utilizando el preprocesador C (habilitado con {-# LANGUAGE CPP #-} ); Creo que sería fácil lograr que Cabal controle un #define basado en el ancho de palabra de la arquitectura de destino. Tenga cuidado, por supuesto, que no son lo mismo; tendrá que tener cuidado de evitar "desbordamientos" en el código Integer y, por ejemplo, Int64 es una instancia de Bounded pero Integer no lo es. Podría ser más simple apuntar a un solo ancho de palabra (y, por lo tanto, escribir) para el rendimiento y vivir con el rendimiento más lento en el otro.

Le sugiero que cree su propio tipo Int52 como un newtype envoltorio sobre Int64 , o un envoltorio Word64 sobre Word64 ; simplemente elija la que mejor se adapte a sus datos, no debería haber un impacto en el rendimiento; si solo fueran bits arbitrarios, iría con Int64 , solo porque Int es más común que Word .

Puede definir todas las instancias para manejar el :info Int64 automáticamente (pruebe :info Int64 en GHCi para averiguar qué instancias desea definir), y proporcione operaciones "inseguras" que solo se aplican directamente bajo el newtype para situaciones críticas de rendimiento en las que Sé que no habrá ningún desbordamiento.

Luego, si no exporta el constructor newtype , siempre puede intercambiar la implementación de Int52 más tarde, sin cambiar el resto de su código. No se preocupe por la sobrecarga de un tipo separado: la representación en tiempo de ejecución de un newtype es completamente idéntica al tipo subyacente; sólo existen en tiempo de compilación.