web-dev-qa-db-fra.com

Changer un entier en chaîne binaire de chiffres

Je travaille actuellement sur une simulation du processeur MIPS en C++ pour une classe d'architecture compacte et j'ai quelques problèmes pour convertir les nombres décimaux en nombres binaires (nombres signés dans les deux sens). Tout fonctionne bien jusqu'au tout dernier moment car mon algorithme actuel tombe dans les zones hors limites pour int on 1 << = 31. Juste besoin d'un coup de pouce dans la bonne direction pour le rendre opérationnel. Merci!

//Assume 32 bit decimal number
string DecimalToBinaryString(int a)
{
    string binary = "";
    int mask = 1;
    for(int i = 0; i < 31; i++)
    {
        if((mask&a) >= 1)
            binary = "1"+binary;
        else
            binary = "0"+binary;
        mask<<=1;
    }
    cout<<binary<<endl;
    return binary;
}

J'inclus aussi mon autre algorithme pour la complétude. Je m'excuse pour le manque de commentaires, mais c'est assez simple.

int BinaryStringToDecimal(string a)
{
    int num = 0;
    bool neg = false;
    if(a.at(0) == '1')
    {
        neg = true;
        for(int x = a.length()-1; x >= 0; x--)
        {
            if(a.at(x) == '1')
                a.at(x) = '0';
            else a.at(x) = '1';
        }
        a.at(a.length()-1) += 1;
        for(int x = a.length()-1; x >= 0; x--)
        {
            if(a.at(x) == '2')
            {
                if(x-1 >= 0)
                {
                    if(a.at(x-1) == '1')
                        a.at(x-1) = '2';
                    if(a.at(x-1) == '0')
                        a.at(x-1) = '1';
                    a.at(x) = '0';
                }
            }
            else if(a.at(x) == '3')
            {
                if(x-1 >= 0)
                    a.at(x-1) += '2';
                a.at(x) = '1';
            }
        }
        if(a.at(0) == '2')
            a.at(0) = '0';
        else if(a.at(0) == '3')
            a.at(0) = '1';
    }
    for(int x = a.length()-1; x >= 0; x--)
    {
        if(a.at(x) == '1')
            num += pow(2.0, a.length()-x-1);
    }
    if(neg)
        num = num*-1;   
    return num;
 }

De plus, si quelqu'un connaît des méthodes efficaces pour les écrire plus efficacement, j'aimerais les entendre. Je n'ai suivi que deux cours d'initiation à la programmation, mais j'ai utilisé différentes techniques pour voir à quel point j'aime leur style.

19
Paul Ruiz

Il existe en réalité des one-liners standard pour ceux-ci.

#include <bitset>

std::string s = std::bitset< 64 >( 12345 ).to_string(); // string conversion

std::cout << std::bitset< 64 >( 54321 ) << ' '; // direct output

std::bitset< 64 > input;
std::cin >> input;
unsigned long ul = input.to_ulong();

Voir cette course comme une démo .

57
Potatoswatter

Remplacer:

if((mask&a) >= 1)

soit:

if ((mask & a) != 0)

ou:

if (mask & a)

Votre problème est que le dernier bit vous donne un nombre négatif, pas positif.

4
Jonathan Leffler

Le problème avec 1 << = 31 a été abordé dans un autre commentaire. En ce qui concerne le code pour la conversion chaîne -> int, vous avez plusieurs options: 

  • convertit la chaîne en flux et utilise l'opérateur >> (int &) défini pour le flux // Correction - peu importe que> :-)
  • utilise la fonction standard C strtol () qui a un argument de base (2 pour binaire)
  • ou si vous voulez vraiment implémenter la conversion vous-même, essayez le code suivant:

    int BinaryStringToDecimal(string a) 
    {
        int Rslt = 0;
        int Mask = 1;
        for (int i = a.length()-1; i >= 0; --i, Mask <<= 1) {
            if (a.at(i) != '0') {
                Rslt |= Mask;
            }
        }
        return (Rslt);
    }
    

Notez que ce code traite différemment les nombres négatifs par rapport à votre code: dans votre fonction, le bit de poids fort est pris en tant que signum. Si le bit le plus à gauche dans l'argument de chaîne de votre fonction n'est pas à la position 32 (en comptant à partir de la droite), votre fonction peut générer des résultats incorrects. Dans le code suggéré ici, il n’existe pas de traitement spécial du signum. Mais si vous obtenez la chaîne de 32 chiffres avec "1" comme le plus à gauche, le MSB dans int résultat sera == 1 et le nombre entier sera négatif (comme il se doit)

0
Pavel Zhuravlev

J'ai vérifié votre code et n'ai trouvé aucune erreur. Voici le code que j'ai utilisé ...

#include <iostream>
#include <string>
using namespace std;

int main ()
{
  int a=1111165117;
  string binary  ("");
    int mask = 1;
    for(int i = 0; i < 31; i++)
    {
    if((mask&a) >= 1)
        binary = "1"+binary;
    else
        binary = "0"+binary;
     mask<<=1;
 }
 cout<<binary<<endl;
 system("PAUSE");         //optional if not using ideone
 return EXIT_SUCCESS;     //optional if not using ideone
 }

La sortie sera 10011100010101110101111010011101 . Si vous pouvez l'exécuter sur ideone

0
Ravi Kumar

Et pourquoi ne pouvez-vous pas simplement convertir int en uint? Il est alors très facile de générer la chaîne binaire car vous n’aurez pas à vous soucier du bit de signe. Il en va de même pour la conversion d'une chaîne binaire en int: le construit en tant que uint, puis le transforme en int:

string DecimalToBinaryString(int a)
{
    uint b = (uint)a;
    string binary = "";
    uint mask = 0x80000000u;
    while (mask > 0)
    {
        binary += ((b & mask) == 0) ? '0' : '1';
        mask >>= 1;
    }
    cout<<binary<<endl;
    return binary;
}

Et, bien sûr, vous pouvez appliquer les optimisations mentionnées, comme pré-allouer le tampon de chaîne, etc.

Aller dans l'autre sens:

uint b = 0;
for (int i = 31; i >=0; --i)
{
    b <<= 1;
    if (a.at(i) == '1')
        b |= 1;
}
int num = (int)b;
0
Jim Mischel