2017-02-03 2 views
1

Sans utiliser les distributions ou les fonctionnalités des bibliothèques, je dois convertir un nombre entier en un nombre flottant avec manipulation de bits. Voici le code sur lequel je travaille actuellement. Il est basé sur le code que j'ai trouvé dans Cast Integer to Float using Bit Manipulation breaks on some integers in C. Le problème que j'ai rencontré concerne les normes d'arrondi dans IEEE 754. Plus précisément mon code arrondit vers 0, mais il devrait arrondir vers des nombres pairs. Quels changements dois-je faire?IEEE 754 Manipulation de bits Erreur d'arrondi

unsigned inttofloat(int x) { 
    int bias = 127; 
    int man; 
    int exp = bias + 31; //8-bit exp 
    int count = 0; 
    int tmin = 1 << 31; 
    int manpattern = 0x7FFFFF; 

    int sign = 0; 

    if (x == 0){ 
     return 0; 
    } 
    else if (x == tmin){ 
     return 0xcf << 24; 
    } 

    if (x < 0) { 
     sign = tmin; 
     x = ~x + 1; // makes x negative so that we can accurately represent it later on. 
    } 

    while((x & tmin) == 0){ 
     exp--; 
     x <<= 1; 
     count++; 
    } 

    exp <<= 23; 
    man = (x >> 8) & manpattern; 

    return (sign | exp | man); 
} 
+1

'int tmin = 1 << 31;' comportement non défini sur une implémentation où 'int' a moins de 33 bits. – EOF

+0

Comment est-ce? En C99, il est dit que le décalage de la taille des mots moins 1 est autorisé là où c'est exactement cela. J'ai 32 bits dans mon entier, donc 31 shift left est toujours bien défini. –

+0

Voici un article qui explique exactement ce @EOF http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html –

Répondre

3

Pour ronde vers le plus proche - liens à même, remplacer (x >> 8) avec:

unsigned u = x; // avoid any potential signed shifting issues 
unsigned lease_significant_bit = (u >> 8) & 1; 
unsigned round_bit = (u >> 7) & 1; // Most significant bit shifted out 
unsigned sticky_bit_flag = !!(u & 0x7F); // All other bits shifts out 

// OP's shifted answer. 
u = (u >> 8): 

// round away if more than half-way or 
// if at half-way and number is odd 
u += (round_bit & sticky_bit_flag) | (round_bit & lease_significant_bit); 

Laissez pour OP simplifier


Notez que u += 1 peut se propager sur toute la à travers et nécessitent une augmentation de l'exposant.

+0

Merci beaucoup pour la réponse. Je suis un peu confus cependant sur où implémenter ceci. vous avez seulement dit de remplacer (x >> 8). Dois-je remplacer cette ligne entière ou garder le & manpattern? –

+0

Le 'u' final pourrait être utilisé comme' man = u & manpattern; ', mais _take time_ pour comprendre le code plutôt que simplement couper/coller. En particulier, si 'x & manpattern == manpattern', alors le' u' propagera le report dû à 'u + = ...' et l'exposant devra augmenter. – chux