2009-03-23 3 views
8

Я учусь C и писать простую программу, которая будет принимать 2 строковые значения, принятые для каждого быть двоичными числами и выполнять арифметические операции в зависимости от выбора пользователя:Лучший способ сделать двоичную арифметику в C?

  • Добавьте два значения,
  • вход Вычесть 2 от ввода 1 или
  • Умножьте два значения.

В моей реализации предполагается, что каждый символ в строке представляет собой двоичный бит, например. char bin5 = "0101";, но кажется слишком наивным подход к синтаксическому анализу через строку персонажа за раз. В идеале я хотел бы напрямую работать с двоичными значениями.

Что является наиболее эффективным способом сделать это в C? Есть ли лучший способ обработать входные данные как двоичные значения, а не scanf() и получить каждый бит из строки?

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

ответ

12

Совет:
Там не так много, что, очевидно, лучше, чем маршировать через строку символа в то время, и убедившись, что пользователь ввел только единицы и нули. Имейте в виду, что даже если вы могли бы написать действительно быстрая сборка, если вы предположите, что все равно 1 или 0, вы действительно не хотите этого делать. Пользователь может ввести что угодно, и вы хотите, чтобы они могли сказать им, если они прищурились или нет.

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

Наконец, для получения ввода от пользователя и записи вывода на экран требуется гораздо больше времени, чем для синтаксического анализа строки или добавления чисел, поэтому ваш алгоритм вряд ли является узким местом здесь. Сохраните свою фантастическую оптимизацию для вещей, которые действительно интенсивно вычисляются :-).

Здесь вы должны сосредоточиться на том, чтобы сделать задачу менее трудоемкой. И, оказывается, кто-то уже сделал это для вас.

Решение:
Взгляните на the strtol() manpage:

long strtol(const char *nptr, char **endptr, int base); 

Это позволит вам преобразовать строку (НПТР) в любой базе, чтобы долго. Он также проверяет ошибки. Пример использование для преобразования двоичной строки:

#include <stdlib.h> 

char buf[MAX_BUF]; 
get_some_input(buf); 

char *err; 
long number = strtol(buf, &err, 2); 
if (*err) { 
    // bad input: try again? 
} else { 
    // number is now a long converted from a valid binary string. 
} 

Поставляя баз 2 говорит strtol для преобразования двоичных литералов.

+0

Негативные бинарные строки строк необычны, поэтому вы, вероятно, захотите использовать strtoul (3) – camh

0

Не было бы проще разобрать строки в целые числа, а затем выполнить ваши математические вычисления по целым числам?

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

+0

Это на самом деле то, что я сделал. Поскольку я не мог найти способ представления чисел в двоичном редиксе в числовом типе данных (в отличие от hexx 0xFF), я выполняю операции над десятичными числами и преобразую их обратно в двоичные значения. Происхождение моего вопроса связано с заданием, но это делается сейчас. – jmlane

3

Прежде всего, я рекомендую вам использовать такие вещи, как strtol, как рекомендовано tgamblin, . Лучше использовать то, что lib дает вам, а не создавать колесо снова и снова.

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

int main() 
{ 
    unsigned int data = 0; 
    int i = 0; 

    char str[] = "1001"; 

    char* pos; 
    pos = &str[strlen(str)-1]; 

    while(*pos == '0' || *pos == '1') 
    { 
     (*pos) -= '0'; 
     data += (*pos) << i; 

     i++; 
     pos--; 
    } 

    printf("data %d\n", data); 
    return 0; 
} 
1

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

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

// General purpose compression removes leading zeroes. 
void compBinNum (char *num) { 
    char *src, *dst; 

    // Find first non-'0' and move chars if there are leading '0' chars. 
    for (src = dst = num; *src == '0'; src++); 
    if (src != dst) { 
     while (*src != '\0') 
      *dst++ = *src++; 
     *dst = '\0'; 
    } 

    // Make zero if we removed the last zero. 
    if (*num == '\0') 
      strcpy (num, "0"); 
} 

Затем обеспечивает функцию клетчатой, которая возвращает либо передается в значении, или NULL, если он был недействителен:

// Check untested number, return NULL if bad. 
char *checkBinNum (char *num) { 
    char *ptr; 

    // Check for valid number. 
    for (ptr = num; *ptr == '0'; ptr++) 
     if ((*ptr != '1') && (*ptr != '0')) 
      return NULL; 

    return num; 
} 

Тогда сама функция ввода:

#define MAXBIN 256 

// Get number from (untrusted) user, return NULL if bad. 
char *getBinNum (char *prompt) { 
    char *num, *ptr; 

    // Allocate space for the number. 
    if ((num = malloc (MAXBIN)) == NULL) 
     return NULL; 

    // Get the number from the user. 
    printf ("%s: ", prompt); 
    if (fgets (num, MAXBIN, stdin) == NULL) { 
     free (num); 
     return NULL; 
    } 

    // Remove newline if there. 
    if (num[strlen (num) - 1] == '\n') 
     num[strlen (num) - 1] = '\0'; 

    // Check for valid number then compress. 
    if (checkBinNum (num) == NULL) { 
     free (num); 
     return NULL; 
    } 
    compBinNum (num); 

    return num; 
} 

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

char *addBinNum (char *num1, char *num2) {...} 
char *mulBinNum (char *num1, char *num2) {...} 

Если пользователь выбирает источник их данные где-нибудь, кроме , вы можете позволить им позвонить checkBinNum(), чтобы проверить его.

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

-1

Предполагая, что строка является двоичным числом просто потому, что она состоит только из цифр из набора {0,1}, является опасной. Например, когда ваш ввод «11», пользователь, возможно, имел в виду одиннадцать в десятичной, а не три в двоичном формате. Именно такая небрежность порождает ужасные ошибки. Ваш ввод неоднозначно неполный, и вы действительно должны запросить, чтобы пользователь также указывал базу.

+0

PS. Обычно, когда люди видят или набирают 11, они, скорее всего, означают одиннадцать, а не три, а старые привычки умирают. – Liberius

+0

Хороший момент. Если бы я делал сценарий общего использования, позволяя пользователю выбирать подходящий выбор, было бы идеально для уменьшения ошибок ввода. В этом конкретном случае использования было установлено, что двоичные значения будут использоваться только для ввода. Тем не менее, лучше всего учитывать специфику в случаях, когда возможна двусмысленность ввода. – jmlane

Смежные вопросы