Оптимизация алгоритма конвертации - PullRequest
2 голосов
/ 08 июля 2011

Я недавно работал над упражнением в книге, которую читал.Задача состояла в том, чтобы создать программу, которая печатает все числа между 1-256 в их двоичном, восьмеричном и шестнадцатеричном эквивалентах.Мы должны были использовать только методы, которые мы изучили до сих пор в книге, что означало только использование циклов for, while и do.. while, операторов if и else if, преобразование целых чисел в эквиваленты ASCII и некоторые более простые вещи (например, cmathiomanip).

Итак, после некоторой работы, вот мой результат.Тем не менее, это грязный и не элегантный и запутанный.У кого-нибудь есть предложения по повышению эффективности кода (или элегантности ...: P) и производительности?

#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;

int main()
{
int decimalValue, binaryValue, octalValue, hexadecimalValue, numberOfDigits;
cout << "Decimal\t\tBinary\t\tOctal\t\tHexadecimal\n\n";
for (int i = 1; i <= 256; i++)
{
    binaryValue = 0;
    octalValue = 0;
    hexadecimalValue = 0;
    if (i != 0) 
    {
    int x, j, e, c, r = i, tempBinary, powOfTwo, tempOctal, tempDecimal;
    for (j = 0; j <=8; j++) //Starts to convert to binary equivalent
    {
        x = pow(2.0, j);
        if (x == i)
        {
              powOfTwo = 1;
              binaryValue = pow(10.0, j);
              break;
        }
        else if (x > i)
        {
              powOfTwo = 0;
              x /= 2;
              break;
        }
    }
    if (powOfTwo == 0)
    {
    for (int k = j-1; k >= 0; k--)
    {
        if ((r-x)>=0)
        {
           r -= x;
           tempBinary = pow(10.0, k);
           x /= 2;
        }
        else if ((r-x)<0)
        {
           tempBinary = 0;
           x /= 2;
        }
        binaryValue += tempBinary;
    }
    } //Finished converting
    int counter = ceil(log10(binaryValue+1)); //Starts on octal equivalent
    int iter;
    if (counter%3 == 0)
    {
       iter = counter/3;
    }
    else if (counter%3 != 0)
    {
       iter = (counter/3)+1; 
    }
    c = binaryValue;
    for (int h = 0; h < iter; h++)
    {
        tempOctal = c%1000;
        int count = ceil(log10(tempOctal+1));
        tempDecimal = 0;
        for (int counterr = 0; counterr < count; counterr++)
        {
            if (tempOctal%10 != 0)
            {
                 e = pow(2.0, counterr);
                 tempDecimal += e;
            }
            tempOctal /= 10;
        }
        octalValue += (tempDecimal * pow(10.0, h));
        c /= 1000;
    }//Finished Octal conversion
    cout << i << "\t\t" << binaryValue << setw(21-counter) << octalValue << "\t\t";
    int c1, tempHex, tempDecimal1, e1, powOf;
    char letter;
    if (counter%4 == 0)//Hexadecimal equivalent
    {
       iter = counter/4;
    }
    else if (counter%4 != 0)
    {
       iter = (counter/4)+1;
    }
    c1 = binaryValue;
    for (int h = 0, g = iter-1; h < iter; h++, g--)
    {
        powOf = g*4;
        if (h == 0)
        {
              tempHex = c1 / pow(10.0, powOf);
        }
        else if (h > 0)
        {
             tempHex = c1 / pow(10.0, powOf);
             tempHex %= 10000;
        }
        int count = ceil(log10(tempHex+1));
        tempDecimal1 = 0;
        for (int counterr = 0; counterr < count; counterr++)
        {
            if (tempHex%10 != 0)
            {
                 e1 = pow(2.0, counterr);
                 tempDecimal1 += e1;
            }
            tempHex /= 10;
        }
        if (tempDecimal1 <= 9)
        {
        cout << tempDecimal1;
        }
        else if (tempDecimal1 > 9)
        {
        cout << char(tempDecimal1+55); //ASCII's numerical value for A is 65. Since 10-15 are supposed to be letters you just add 55
        }
    }
    cout << endl;
    }
}
system("pause");
return 0;
}

Буду признателен за любые рекомендации по улучшению.

Ответы [ 7 ]

6 голосов
/ 08 июля 2011

Вы уже покрыли «iomanip», что означает, что вы уже покрыли «iostream».

Если это так, взгляните на следующее:

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

int x = 250;
cout << dec << x << " " 
     << oct << x << " "
     << hex << x << "\n"
     << x << "\n";       // This will still be in HEX
5 голосов
/ 08 июля 2011

Выделите функции для каждого типа вывода, затем выполните цикл по списку целых чисел и выведите каждую по очереди, вызывая функцию для каждого отдельного формата.

for (int i = 1; i <= 256; ++i)
{
  printBin(i);
  printHex(i);
  printOct(i);
}

Фундаментальная проблема заключается в том, что эта функция требует рефакторинга, чтобы стать более модульной. Представьте, что вы пишете код для использования кем-то другим. Как они могут назвать ваш main? Как они понимают, что делает каждый раздел кода? Они не могут. Если вы сделаете каждый раздел кода, который выполняет определенную работу, вызываемым как функция, тогда будет легче понять его назначение и использовать его позже.

2 голосов
/ 08 июля 2011

Рассматривали ли вы написание общей функции, которая работает с любой базой?

Преобразовать неотрицательное число в общую базу очень просто ... вам просто нужно вычислить number % base, и вы получите наименее значащую цифру, затем разделите number на base и повторите, чтобы получить другие цифры. ..

std::string converted_number;
do {
    int digit = number % base;
    converted_number = digits[digit] + converted_number;
    number = number / base;
} while (number != 0);

Если у вас есть универсальная функция преобразования, то решение вашей проблемы легко ... просто вызовите ее с base = 2, 8 и 16, чтобы получить нужные вам результаты в виде строк.

1 голос
/ 08 июля 2011

Мой ответ может быть немного ненормальным, но

 printf ("%u %o %x \n", value, value, value);

сделает трюк для восьмеричной и шестнадцатеричной версий;)

Для двоичной версии я бы использовал флаг, инициализированный 256, и сравнил бы его с вашим числом с оператором AND. Если true, выведите 1, если нет, выведите 0. Затем разделите флаг на два. Повторяйте до тех пор, пока флаг не станет 1.

Псевдокод для преобразования из целого числа в двоичное

int flag = 256
do 
{
if (flag && value)
print "1"
else
print "0"
flag = flag >> 1 // aka divide by two, if my memory serves well
} while flag > 1

Что касается восьмеричных и шестнадцатеричных значений, я немного заржавел, но оглядываясь вокруг, вы сможете найти образцы, которые вы можете адаптировать.

0 голосов
/ 08 июля 2011

Может как то так?

#include "stdio.h"
int main(){
    char Chars[16]= {48,49,50,51,52,53,54,55,56,57,65,66,67,68,69,70};
    for(int n = 1;n != 256; n++)
    {
        {//decimal
            printf("%i\t", n); 
        }
        {//Hexadecimal
            char L, R;
            R = (n & 0x0F) >> 0;
            L = (n & 0xF0) >> 4;
            printf("%c%c\t", Chars[L], Chars[R]);
        }
        {//Octal
            char L, M, R;
            R = (n & 0x07) >> 0;
            M = (n & 0x38) >> 3;
            L = (n & 0xC0) >> 6;
            printf("%c%c%c\t", Chars[L], Chars[M], Chars[R]);
        }
        {//Binary
            char B0, B1, B2, B3, B4, B5, B6, B7;
            B0 = (n & 0x01) >> 0;
            B1 = (n & 0x02) >> 1;
            B2 = (n & 0x04) >> 2;
            B3 = (n & 0x08) >> 3;
            B4 = (n & 0x10) >> 4;
            B5 = (n & 0x20) >> 5;
            B6 = (n & 0x40) >> 6;
            B7 = (n & 0x80) >> 7;
            printf("%c%c%c%c%c%c%c%c\n", Chars[B0], Chars[B1], Chars[B2], Chars[B3], Chars[B4], Chars[B5], Chars[B6], Chars[B7]);
        }
        printf("256\t100\t400\t100000000\n");
    }
}
0 голосов
/ 08 июля 2011

Попробуйте это

using namespace std;

template <typename T>
inline void ShiftMask(T& mask) {
    mask = (mask >> 1) & ~mask;
}

template < typename T >
std::ostream& bin(T& value, std::ostream &o)
{
    T mask = 1 << (sizeof(T) * 8 - 1);

    while (!(value & mask) && (mask != 0)) ShiftMask(mask);

    while (mask) {
        o << (value & mask ? '1' : '0');
        ShiftMask(mask);
    }

    return o;
}

int main(void) {
  for (int i=0; i<256;i++) {
    bin(a, std::cout);
    cout << " " << oct << i;
    cout << " " << dec << i;
    cout << " " << hex << i;
    cout << ""
  }
}
0 голосов
/ 08 июля 2011

Зачем делать это сложнее, чем на самом деле.

for (int i = 1; i <= 256; ++i)
{
    std::cout << std::dec << i << "\t" << std::oct << i << "\t" << std::hex << i << std::endl;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...