1
votes

Convertir FP32 en Bfloat16 en C ++

Comment puis-je convertir de float (signe 1 bit, exp 8 bits, mantisse 23 bits) en Bfloat16 (signe 1 bit, exp 8 bits, mantisse 7 bits) en C ++?


3 commentaires

frexp peut être utilisé pour casser un float vers le bas dans les composants. Le réassembler dans la structure que vous appelez Bfloat16 reste un exercice pour le lecteur.


J'imagine que vous voulez le faire efficacement, car la seule raison d'un si petit format à virgule flottante est lorsque vous en avez un très grand nombre. J'imagine également qu'il faut arrondir correctement.


@IgorTandetnik mais ce serait cher. Bfloat16 est conçu comme la moitié supérieure du flotteur afin que vous puissiez le tronquer facilement


3 Réponses :



1
votes

Comme démontré dans la réponse de Botje , il suffit de copier la moitié supérieure du float valeur puisque les modèles de bits sont les mêmes. La façon dont cela est fait dans cette réponse enfreint les règles concernant l'aliasing strict en C ++. La solution consiste à utiliser memcpy pour copier les bits.

float_val *= 1.001957f;

S'il est nécessaire d'arrondir le résultat plutôt que de le tronquer, vous pouvez multiplier par une valeur magique pour pousser certains de ces bits inférieurs dans les bits supérieurs.

static inline tensorflow::bfloat16 FloatToBFloat16(float float_val)
{
    tensorflow::bfloat16 retval;
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
    memcpy(&retval, &float_val, sizeof retval);
#else
    memcpy(&retval, reinterpret_cast<char *>(&float_val) + sizeof float_val - sizeof retval, sizeof retval);
#endif
    return retval;
}


0 commentaires

1
votes

memcpy ne compilerait pas pour moi dans le cas du petit boutiste pour une raison quelconque. C'est ma solution. Je l'ai comme structure ici pour que je puisse facilement accéder aux données et parcourir différentes plages de valeurs pour confirmer que cela fonctionne correctement.

struct bfloat16{
   unsigned short int data;
   public:
   bfloat16(){
      data = 0;
   }
   //cast to float
   operator float(){
      unsigned int proc = data<<16;
      return *reinterpret_cast<float*>(&proc);
   }
   //cast to bfloat16
   bfloat16& operator =(float float_val){
      data = (*reinterpret_cast<unsigned int *>(&float_val))>>16;
      return *this;
   }
};

//an example that enumerates all the possible values between 1.0f and 300.0f
using namespace std;

int main(){
   bfloat16 x;
   for(x = 1.0f; x < 300.0f; x.data++){
      cout<<x.data<<" "<<x<<endl;
   }
   
   return 0;
}


0 commentaires