2012-03-15 12 views
9

Necesito almacenar valores en un rango de aproximadamente -10000 a 10000. En los límites del rango, la precisión necesaria no es muy alta (tal vez alrededor de 64, veré cómo encaja)), alrededor de cero, la precisión debe ser 1 o mejor.Buscando una biblioteca flotante medio o flotante

Desafortunadamente el espacio es muy limitado, no más de 12 bits, menos sería aún mejor. Tan estrictamente hablando, incluso half floats están fuera. ¿Hay una biblioteca de código abierto que maneja algunos formatos de flotación muy cortos con mantisa corta y longitud de exponente? Al igual que la mantisa de 8 bits y el exponente de 3 bits.

Solo se requiere conversión desde/a formatos más grandes, no se realiza aritmética.

+0

Con un exponente de 3 bits, obtendría una precisión mínima de 128. – xanatos

+0

Sí, lo más probable es que termine cocinando algo solo con bitfields. Pero estoy interesado en ver las soluciones que otros han encontrado, si es que las hay. – hirschhornsalz

+0

@xanatos: solo si te quedas con un radix de 2. Si cambias a un radix de 10, solo necesita mantisa de 9 bits, radix de 2 bit. (Precisión de 39 cerca de 10000) –

Respuesta

3

Quizás μ-law o A-law podría ser útil para usted.

+1

oh, pensamiento interesante. Deberías ampliar esta respuesta. Mucho. –

+0

Si es preciso al 1 más cercano de 0-12, precisión 2 de 13-25, precisión 3 de 26-38 ... ¡esa es la precisión 39 de 9671-10139, y cabe en 9 bits! (dejando décimo bit por signo) no tengo ni idea de cómo hacer los cálculos para esto. –

+0

Muy interesante. Implementé algo muy simple con solo 4 rangos en mi código anterior. Ahora intentaré encontrar una generalización o abstracción eficiente y ver qué proporción de rangos/valores se ajusta mejor. – hirschhornsalz

4

Si no está haciendo ningún cálculo, entonces apenas hay necesidad de una biblioteca. frexp, ldexp y algunos movimientos de bits deberían hacer el trabajo.

2

Utilizamos libHalf que viene con openexr. No soy un gran admirador de esto ya que la calidad del código no es exactamente estelar (aunque tampoco está seriamente roto). Busque el directorio llamado Half en las fuentes extraídas, debe ser independiente.

1

Extrapolando a partir de la respuesta de Jens Björnhager, tengo esto:

double from_storage(unsigned short bits) { //only lowest 10 bits read 
     double a = bits&0x1FF; 
     a /= 5.11967985; 
     a = a*a; 
     return double(bits&0x200 ? -a : a); 
} 

unsigned short to_storage(double a) { //only lowest 10 bits set/relevant 
     assert(a<=10000.0); 
     assert(a>=-10000.0); 
     if (a >= 0) { 
       a = std::pow(a, .5); // inverse of number in from_storage 
       a *= 5.11967985; 
       unsigned short b = ((unsigned short)(a)); 
       assert((b&0x200)==0); 
       return b; 
     } else { 
       a = std::pow(-a, .5); 
       a *= 5.11967985; 
       unsigned short b = ((unsigned short)(a)); 
       assert((b&0x200)==0); 
       return b | 0x200; 
     } 
} 

como se ha demostrado en http://ideone.com/DLTUn. Esto puede mantener cada uno de los valores entre -10 y 10 de forma exclusiva, y los valores superiores están separados solo por 39. (También hay 3 valores entre 0 y 1). Alguien más mathy probablemente podría obtener el positivo y el negativo a más de un formato de "dos cumplidos", que cortaría el código to_storage a la mitad.

+1

Gracias por su contribución. Creo que usaré alguna variante de μ-Law (que es muy similar a un quarter float) extendida a 11 o 12 bits. Necesito almacenar varios 10^9 de estos valores (cuanto más, mejor), esa es la razón principal por la que quiero guardar cada bit. La velocidad de conversión es otra preocupación: es más probable que el pow se desacelere, pero un enfoque basado en tablas funcionará. – hirschhornsalz

+0

@drhirsch: esto funciona en la misma línea que μ-Law, excepto con una curva suave. Un enfoque basado en tablas podría ser más rápido, pero sería más complicado.Creo que la mesa es la mejor respuesta en todos. –