Detalles de implementación del hardware del divisor de punto flotante

Estoy tratando de implementar un divisor de hardware de coma flotante de 32 bits en el hardware y me pregunto si puedo obtener alguna sugerencia sobre algunas concesiones entre diferentes algoritmos.

Mi unidad de punto flotante actualmente admite multiplicación y sum / resta, pero no voy a cambiarla a una architecture de coma flotante de fusión y multiplicación (FMA) ya que esta es una plataforma integrada en la que bash minimizar el uso del área.

Hace mucho tiempo me encontré con este algoritmo de división flotante / punto fijo limpio y fácil de implementar utilizado en FPU militares de ese período de tiempo:

  1. la entrada debe estar sin signo y desplazada de modo que x < y ambos estén dentro del rango < 0.5 ; 1 > < 0.5 ; 1 >

    no te olvides de guardar la diferencia de turnos sh = shx - shy señales sh = shx - shy y originales

  2. encuentra f (iterando) entonces y*f -> 1 .... después de eso x*f -> x/y que es el resultado de la división

  3. desplaza la x*f hacia atrás por sh y restaura el signo de resultado (sig=sigx*sigy)

    el x*f se puede calcular fácilmente así:

     z=1-y (x*f)=(x/y)=x*(1+z)*(1+z^2)*(1+z^4)*(1+z^8)*(1+z^16)...(1+z^2n) 

    dónde

     n = log2(num of fractional bits for fixed point, or mantisa bit size for floating point) 

    También puede detenerse cuando z^2n es cero en tipos de datos de ancho de bit fijo.

[Edit2] Tuve un poco de tiempo y ánimo para esto, así que aquí la implementación IEEE 754 C ++ de 32 bits

Eliminé los ejemplos anteriores (bignum) para evitar confusiones para los lectores futuros (todavía se puede acceder en el historial de edición si es necesario)

 //--------------------------------------------------------------------------- // IEEE 754 single masks const DWORD _f32_sig =0x80000000; // sign const DWORD _f32_exp =0x7F800000; // exponent const DWORD _f32_exp_sig=0x40000000; // exponent sign const DWORD _f32_exp_bia=0x3F800000; // exponent bias const DWORD _f32_exp_lsb=0x00800000; // exponent LSB const DWORD _f32_exp_pos= 23; // exponent LSB bit position const DWORD _f32_man =0x007FFFFF; // mantisa const DWORD _f32_man_msb=0x00400000; // mantisa MSB const DWORD _f32_man_bits= 23; // mantisa bits //--------------------------------------------------------------------------- float f32_div(float x,float y) { union _f32 // float bits access { float f; // 32bit floating point DWORD u; // 32 bit uint }; _f32 xx,yy,zz; int sh; DWORD zsig; float z; // result signum abs value xx.f=x; zsig =xx.u&_f32_sig; xx.u&=(0xFFFFFFFF^_f32_sig); yy.f=y; zsig^=yy.u&_f32_sig; yy.u&=(0xFFFFFFFF^_f32_sig); // initial exponent difference sh and normalize exponents to speed up shift in range sh =0; sh-=((xx.u&_f32_exp)>>_f32_exp_pos)-(_f32_exp_bia>>_f32_exp_pos); xx.u&=(0xFFFFFFFF^_f32_exp); xx.u|=_f32_exp_bia; sh+=((yy.u&_f32_exp)>>_f32_exp_pos)-(_f32_exp_bia>>_f32_exp_pos); yy.u&=(0xFFFFFFFF^_f32_exp); yy.u|=_f32_exp_bia; // shift input in range while (xx.f> 1.0f) { xx.f*=0.5f; sh--; } while (xx.f< 0.5f) { xx.f*=2.0f; sh++; } while (yy.f> 1.0f) { yy.f*=0.5f; sh++; } while (yy.f< 0.5f) { yy.f*=2.0f; sh--; } while (xx.f<=yy.f) { yy.f*=0.5f; sh++; } // divider block z=(1.0f-yy.f); zz.f=xx.f*(1.0f+z); for (;;) { z*=z; if (z==0.0f) break; zz.f*=(1.0f+z); } // shift result back for (;sh>0;) { sh--; zz.f*=0.5f; } for (;sh<0;) { sh++; zz.f*=2.0f; } // set signum zz.u&=(0xFFFFFFFF^_f32_sig); zz.u|=zsig; return zz.f; } //--------------------------------------------------------------------------- 

Quería mantenerlo simple, por lo que aún no está optimizado. Puede, por ejemplo, reemplazar todo *=0.5 y *=2.0 por exponente inc/dec ... Si compara los resultados FPU en operador float / esto será un poco menos preciso porque la mayoría de las FPU calculan en formato interno de 80 bits y esta implementación está solo en 32 bits.

Como puedes ver, estoy usando desde FPU solo +,-,* . Las cosas se pueden acelerar usando algoritmos rápidos de sqr como

  • Cálculo rápido de cuadrados bignum

especialmente si quieres usar anchuras de gran tamaño ...

No olvide implementar la corrección de normalización y / o desbordamiento / desbordamiento.