2010-06-11 17 views
8

¿Puede alguien explicarme cómo convierto un valor de coma flotante de 32 bits en un valor de coma flotante de 16 bits?Float32 to Float16

(s signo = e = exponente y mantisa m =)

Si 32 bits flotante es 1s7e24m
y el flotador 16 bits es 1s5e10m

entonces es tan simple como hacer?

int  fltInt32; 
short fltInt16; 
memcpy(&fltInt32, &flt, sizeof(float)); 

fltInt16 = (fltInt32 & 0x00FFFFFF) >> 14; 
fltInt16 |= ((fltInt32 & 0x7f000000) >> 26) << 10; 
fltInt16 |= ((fltInt32 & 0x80000000) >> 16); 

Supongo que NO ES así de simple ... así que ¿alguien me puede decir lo que HAGA que hacer?

Editar: Puedo ver que tengo mi exponente desplazarse mal ... ¿así ESTO sería mejor?

fltInt16 = (fltInt32 & 0x007FFFFF) >> 13; 
fltInt16 |= (fltInt32 & 0x7c000000) >> 13; 
fltInt16 |= (fltInt32 & 0x80000000) >> 16; 

Espero que esto sea correcto. Disculpas si me falta algo obvio que se ha dicho. Es casi medianoche un viernes por la noche ... así que no estoy "del todo" sobrio;)

Edit 2: Ooops. Lo fastidié de nuevo. ¡Quiero perder los 3 mejores bits, no los más bajos! Así que ¿qué tal esto:

fltInt16 = (fltInt32 & 0x007FFFFF) >> 13; 
fltInt16 |= (fltInt32 & 0x0f800000) >> 13; 
fltInt16 |= (fltInt32 & 0x80000000) >> 16; 

código final debe ser:

fltInt16 = ((fltInt32 & 0x7fffffff) >> 13) - (0x38000000 >> 13); 
fltInt16 |= ((fltInt32 & 0x80000000) >> 16); 
+2

Creo que esto ya fue preguntado (y respondido) aquí: http://stackoverflow.com/questions/1659440/32-bit-to-16-bit-floating-point-conversion – humbagumba

+0

podría ser así de simple, pero pierdes precisión a menos que float32 no use toda la "precisión" que tiene ... básicamente, obtienes 5/7 de los bits de exp (tomas por supuesto los más significativos), y 10/24 de la mantisa; estas proporciones dicen de alguna manera cuánto puede perder en la conversión. Exactamente como ocurre si quiere ajustar un entero de 32 bits en un entero de 16 bits ... el rango de números representables en la pantalla es más pequeño; "cortar" la mantisa reduce la "precisión", y el exponente también limita el rango: 5 bits firmados dan -16 a +15, contra -64/+ 63 (si lo hice bien ...: D tarde) – ShinTakezou

+0

@ShinTakezou: ¿Seguro que no es posible perder 16 bits de datos y NO perder precisión? Float16 es mucho menos preciso y, por lo tanto, tiene menos precisión automáticamente ... ¿o no te estoy entendiendo bien? – Goz

Respuesta

4

Los exponentes en su float32 y float16 representaciones son probablemente sesgada, y sesgada de manera diferente. Necesita desvincular el exponente que obtuvo de la representación float32 para obtener el exponente real, y luego desviarlo para la representación float16.

Aparte de este detalle, creo que es tan simple como eso, pero todavía me sorprenden las representaciones de punto flotante de vez en cuando.

EDIT:

  1. Compruebe si hay desbordamiento cuando se hace la cosa con los exponentes mientras estás en ello.

  2. Su algoritmo trunca los últimos bits de la mantisa un poco abruptamente, que pueden ser aceptables, pero es posible que desee implementar, digamos, redondear a la aproximación mirando los bits que están a punto de descartarse. "0 ..." -> redondear hacia abajo, "100..001 ..." -> redondear hacia arriba, "100..00" -> redondear a par.

+0

Los números de coma flotante de 32 bits en el estándar IEEE754 tienen 23 bits de mantisa y 8 bits de exponente. – bbudge

+0

@bbudge ... bastante justo, estaba tratando de hacerlo de memoria. Me llevé la parte equivocada, evidentemente;) – Goz

4

El exponente tiene que ser imparcial, sujeta y rebiased. Este es el código rápido que utilizo:

unsigned int fltInt32; 
unsigned short fltInt16; 

fltInt16 = (fltInt32 >> 31) << 5; 
unsigned short tmp = (fltInt32 >> 23) & 0xff; 
tmp = (tmp - 0x70) & ((unsigned int)((int)(0x70 - tmp) >> 4) >> 27); 
fltInt16 = (fltInt16 | tmp) << 10; 
fltInt16 |= (fltInt32 >> 13) & 0x3ff; 

Este código será aún más rápido con una tabla de consulta para el exponente, pero yo uso esta porque se adapta fácilmente a un flujo de trabajo SIMD.

Limitaciones de la aplicación:

  • valores desbordantes que no pueden ser representados en float16 dará valores no definidos.
  • Los valores infrautilizados devolverán un valor indefinido entre 2^-15 y 2^-14 en lugar de cero.
  • Denormals dará valores indefinidos.

Ten cuidado con los denormales. Si su arquitectura los usa, pueden ralentizar su programa tremendamente.