Восьмеричное преобразование с использованием циклов в C ++ - PullRequest
0 голосов
/ 07 июля 2011

В настоящее время я работаю над базовой программой, которая преобразует двоичное число в восьмеричное. Его задача состоит в том, чтобы напечатать таблицу со всеми числами от 0 до 256, с их двоичным, восьмеричным и шестнадцатеричным эквивалентом. Задача требует, чтобы я использовал только мой собственный код (т.е. используя циклы и т. Д., А не встроенные функции). Код, который я сделал (на данный момент он довольно грязный), выглядит следующим образом (это всего лишь фрагмент):

        int counter = ceil(log10(fabs(binaryValue)+1));
        int iter;
        if (counter%3 == 0)
        {
            iter = counter/3;
        }
        else if (counter%3 != 0)
        {
            iter = ceil((counter/3)); 
        }
        c = binaryValue;
        for (int h = 0; h < iter; h++)
        {
            tempOctal = c%1000;
            c /= 1000;
            int count = ceil(log10(fabs(tempOctal)+1));
            for (int counter = 0; counter < count; counter++)
            {
                if (tempOctal%10 != 0)
                {
                   e = pow(2.0, counter);
                   tempDecimal += e;
                }
                tempOctal /= 10;
            }
            octalValue += (tempDecimal * pow(10.0, h));
        }

Вывод совершенно неверный. Когда, например, двоичный код 1111 (десятичное значение 15), он выводит 7. Я могу понять, почему это происходит (последние три цифры в двоичном числе 111 - 7 в десятичном формате), но не может выявить проблему в коде. Есть идеи?

Редактировать: После некоторой отладки и тестирования я понял ответ.

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

int main()
{
    while (true)
{
    int binaryValue, c, tempOctal, tempDecimal, octalValue = 0, e;
    cout << "Enter a binary number to convert to octal: ";
    cin >> binaryValue;
    int counter = ceil(log10(binaryValue+1));
    cout << "Counter " << counter << endl;
    int iter;
    if (counter%3 == 0)
    {
       iter = counter/3;
    }
    else if (counter%3 != 0)
    {
       iter = (counter/3)+1; 
    }
    cout << "Iterations " << iter << endl;
    c = binaryValue;
    cout << "C " << c << endl;
    for (int h = 0; h < iter; h++)
    {
        tempOctal = c%1000;
        cout << "3 digit binary part " << tempOctal << endl;
        int count = ceil(log10(tempOctal+1));
        cout << "Digits " << count << endl;
        tempDecimal = 0;
        for (int counterr = 0; counterr < count; counterr++)
        {
            if (tempOctal%10 != 0)
            {
                 e = pow(2.0, counterr);
                 tempDecimal += e;
                 cout << "Temp Decimal value 0-7 " << tempDecimal << endl;
            }
            tempOctal /= 10;
        }
        octalValue += (tempDecimal * pow(10.0, h));
        cout << "Octal Value " << octalValue << endl;
        c /= 1000;
    }
cout << "Final Octal Value: " << octalValue << endl;
}
system("pause");
return 0;

}

Ответы [ 5 ]

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

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

Конечно, очевидное решение состоит в том, чтобы использовать уже существующую функцию для этого (например, { char buf[32]; snprintf(buf, sizeof buf, "%o", binaryValue); } и все готово, но если вы действительно хотите сделать это «вручную», вам следует изучить использование битовых операций :

  • Используйте binaryValue & 3, чтобы замаскировать три младших бита. Это будет ваша следующая восьмеричная цифра (три бита - 0,7, то есть одна восьмеричная цифра).
  • используйте binaryValue >>= 3 для сдвига числа, чтобы получить три новых бита в самой низкой позиции
  • Обратное число после этого или (если возможно) начало с конца строкового буфера и выдача цифр назад
1 голос
/ 07 июля 2011

Он не понимает ваш код; это кажется слишком сложным. Но один Конечно, если вы конвертируете внутреннее представление в восьмерично, вам нужно где-то разделить на 8 и сделать % 8 где-то. И я их не вижу. С другой стороны, я вижу оба операции с 10 и 1000, ни одна из которых не должна присутствовать.

Для начала, вы можете написать простую функцию, которая преобразует значение (предпочтительно unsigned некоторого типа & mdash; получить unsigned прямо перед тем, как беспокоиться о знаке) на строку, используя любую базу, например ::

//! \pre
//!     base >= 2 && base < 36
//!
//! Digits are 0-9, then A-Z.
std::string convert(unsigned value, unsigned base);

Это не должно занимать более 5 или 6 строк кода. Но внимание, нормальный алгоритм генерирует цифры в обратном порядке: если вы используя std::string, самое простое решение - push_back каждая цифра, затем позвоните std::reverse в конце, прежде чем вернуть его. В противном случае: Стиль C char[] работает хорошо, если вы сделаете его достаточно большим. (sizeof(unsigned) * CHAR_BITS + 2 более чем достаточно, даже для подписанный, и даже с '\0' в конце, который вам не понадобится, если вы верните строку.) Просто инициализируйте указатель на buffer + sizeof(buffer) и выполняйте предварительное уменьшение при каждом добавлении цифры. к создайте возвращаемую строку: std::string( pointer, buffer + sizeof(buffer) ) должен сделать трюк.

Что касается цикла, конечное условие может быть просто value == 0. (Вы будете делить value на base каждый раз, так что вы гарантированно достигнет этого условия.) Если вы используете do ... while, вместо while, вам также гарантируется как минимум одна цифра выход.

(Мне было бы намного проще просто опубликовать код, но так как это, очевидно, домашнее задание, я думаю, что лучше просто дать показания относительно того, что должно быть сделано.)

Редактировать: Я добавил свою реализацию и некоторые комментарии к вашей новой код:

Сначала для комментариев: очень вводящее в заблуждение приглашение: «Введите двоичное число "звучит так, как будто пользователь должен ввести двоичное; если вы при чтении в int вводимое значение должно быть десятичным. И здесь все еще % 1000 и / 1000 и % 10 и / 10, которые я не делаю Понимаю. Что бы вы ни делали, это не может быть правильным, если нет % 8 и / 8. Попробуйте: введите "128", например, и посмотрите, что вы получите.

Если вы пытаетесь ввести двоичный файл, то вам действительно нужно ввести строка и разбери сам.

Мой код для самого преобразования:

//! \pre
//!     base >= 2 && base <= 36
//!
//! Digits are 0-9, then A-Z.
std::string toString( unsigned value, unsigned base )
{
    assert( base >= 2 && base <= 36 );
    static char const digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    char buffer[sizeof(unsigned) * CHAR_BIT];
    char* dst = buffer + sizeof(buffer);
    do
    {
        *--dst = digits[value % base];
        value /= base;
    } while (value != 0);
    return std::string(dst, buffer + sizeof(buffer));
}

Если вы хотите проанализировать ввод (например, для двоичного файла), то что-то вроде следующие должны сделать трюк:

unsigned fromString( std::string const& value, unsigned base )
{
    assert( base >= 2 && base <= 36 );
    static char const digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    unsigned results = 0;
    for (std::string::const_iterator iter = value.begin();
            iter != value.end();
            ++ iter)
    {
        unsigned digit = std::find
            ( digits, digits + sizeof(digits) - 1,
              toupper(static_cast<unsigned char>( *iter ) ) ) - digits;
        if ( digit >= base )
            throw std::runtime_error( "Illegal character" );
        if ( results >= UINT_MAX / base
             && (results > UINT_MAX / base || digit > UINT_MAX % base) )
            throw std::runtime_error( "Overflow" );
        results = base * results + digit;
    }
    return results;
}

Это сложнее, чем toString, потому что он должен обрабатывать все виды возможных состояний ошибки. Это также все еще, вероятно, проще, чем вы необходимость; Вы, вероятно, хотите обрезать заготовки и т. д., а также (или даже игнорировать их: ввод 01000000 более подвержен ошибкам, чем 0100 0000).

(Кроме того, конечный итератор для find имеет - 1 из-за трейлинга '\0' компилятор вставляет в digits.)

0 голосов
/ 15 октября 2012
#include <cmath>
#include <iostream>
#include <string>
#include <cstring>
#include <cctype>
#include <cstdlib>

using namespace std;

char*  toBinary(char* doubleDigit)
{
  int digit = atoi(doubleDigit);
  char* binary = new char();

  int x = 0 ;
  binary[x]='(';
  //int tempDigit = digit;
 int k=1;
  for(int i = 9 ; digit != 0; i--)
  {
    k=1;//cout << digit << endl;
    //cout << "i"<< i<<endl;
    if(digit-k *pow(8,i)>=0)
    {


      k =1;
      cout << "i" << i << endl;
      cout << k*pow(8,i)<< endl;

      while((k*pow(8,i)<=digit))
      {
    //cout << k <<endl;
    k++;
      }
      k= k-1;



       digit = digit -k*pow(8,i);

      binary[x+1]= k+'0';
      binary[x+2]= '*';
      binary[x+3]= '8';
      binary[x+4]='^';
      binary[x+5]=i+'0';
      binary[x+6]='+';

    x+=6;

    }

  }
  binary[x]=')';
  return binary;
}

int main()
{
 char value[6]={'4','0','9','8','7','9'};



 cout<< toBinary(value); 



  return 0 ;
}
0 голосов
/ 07 июля 2011

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

Я думаю, что ваш алгоритм неверен. Просто глядя на это, я вижу функцию, которая возводится в квадрат к концу. Зачем? Существует простой математический способ сделать то, о чем вы говорите. Как только вы получите математическую часть, вы можете преобразовать ее в код.

Если у вас был карандаш и бумага, а калькулятора нет (похоже на то, что вы не использовали предварительно созданные функции), метод состоит в том, чтобы взять базу, на которой вы находитесь, изменить ее на базу 10, а затем перейти на нужную базу. В вашем случае это будет база 8, база 10, база 2.

Это должно помочь вам начать. Все, что вам действительно нужно - это операторы if / else с модулем для получения остатков. http://www.purplemath.com/modules/numbbase3.htm

Затем вы должны выяснить, как получить желаемый результат. Может быть, сохранить остатки в массиве или вывод в текстовый файл.

(Для таких проблем я хочу удвоить мажор с применением математики)

Так как вы хотите преобразовать из десятичного числа 0-256, было бы проще создать функции, скажем, вызвать их int binary (), char hex () и int octal (). Сначала делайте двоичные и восьмеричные, поскольку это будет проще всего, поскольку они могут быть представлены только целыми числами.

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

На самом деле я не понимаю, зачем вам такой сложный код, чтобы выполнить то, что вам нужно.

Прежде всего, нет такой вещи, как преобразование из двоичного в восьмеричное (То же самое верно для преобразования в / из десятичного числа и т. д.).Машина всегда работает в двоичном формате, с этим вы ничего не можете (или не должны) сделать.

На самом деле это вопрос форматирования .То есть, как вы печатаете число в виде восьмеричного числа, и как вы разбираете текстовое представление восьмеричного числа.*

Вы можете использовать следующий код для печати числа на любой базе:

const int PRINT_NUM_TXT_MAX = 33; // worst-case for binary

void PrintNumberInBase(unsigned int val, int base, PSTR szBuf)
{
    // calculate the number of digits
    int digits = 0;
    for (unsigned int x = val; x; digits++)
        x /= base;

    if (digits < 1)
        digits = 1; // will emit zero

    // Print the value from right to left

    szBuf[digits] = 0; // zero-term

    while (digits--)
    {
        int dig = val % base;
        val /= base;

        char ch = (dig <= 9) ?
            ('0' + dig) :
            ('a' + dig - 0xa);

        szBuf[digits] = ch;
    }
}

Пример:

char sz[PRINT_NUM_TXT_MAX];
PrintNumberInBase(19, 8, sz);
...