8

私は C を学習し、それぞれが 2 進数であると想定される 2 つの文字列値を取り、ユーザーの選択に従って算術演算を実行する簡単なプログラムを作成しています。

  • 2 つの値を加算し、
  • 入力 1 から入力 2 を引く、または
  • 2 つの値を乗算します。

私の実装では、文字列内の各文字がバイナリ ビットであると想定しchar bin5 = "0101";ています。理想的には、バイナリ値を直接操作したいと思います。

Cでこれを行う最も効率的な方法は何ですか? scanf()文字列から各ビットを取得するのではなく、入力をバイナリ値として扱うより良い方法はありますか?

いくつかの調査を行いましたが、初心者の観点から明らかに優れたアプローチは見つかりませんでした。任意の提案をいただければ幸いです!

4

5 に答える 5

12

アドバイス:
一度に 1 文字ずつ文字列を行進し、ユーザーが 1 と 0 だけを入力したことを確認するよりも明らかに優れていることはほとんどありません。すべてがorであると仮定すると、非常に高速なアセンブリ ルーチンを作成できますが、実際にはそうしたくないことに注意してください。ユーザーは何でも入力できますが、失敗したかどうかをユーザーに伝えたいと考えています。10

実際の数値を加算するのにおそらくかかる数サイクルと比較すると、これは気が遠くなるほど遅いように見えるのは事実ですが、ナノ秒またはミリ秒で答えが得られるかどうかは本当に重要ですか? とにかく、人間は 30 ミリ秒の遅延しか検出できません。

最後に、文字列を解析したり数値を追加したりするよりも、ユーザーからの入力を取得して画面に出力を書き込むのにはるかに長い時間がかかるため、ここではアルゴリズムがボトルネックになることはほとんどありません。実際に計算量が多いもののための派手な最適化を保存してください:-)。

ここで注目すべきは、タスクのマンパワー集約度を下げることです。そして、誰かがすでにあなたのためにそれを行っていることがわかりました.

解決策:マンページ
を見てくださいstrtol():

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

これにより、任意の基数の文字列 (nptr) を long に変換できます。エラーもチェックします。バイナリ文字列を変換するための使用例:

#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すると、バイナリ リテラルを変換するように指示されます。

于 2009-03-23T05:26:48.497 に答える
4

最初に、tgamblin が推奨する strtol のようなものを使用することをお勧めします。ホイールを何度も作成するのではなく、ライブラリが提供するものを使用することをお勧めします。

しかし、CI が 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;
}
于 2009-03-23T06:26:35.157 に答える
1

最高のパフォーマンスを得るには、関数への信頼できる入力と信頼できない入力を区別する必要があります。

たとえばgetBinNum()、ユーザーからの入力を受け入れるような関数は、有効な文字をチェックし、圧縮して先頭のゼロを削除する必要があります。まず、汎用のインプレース圧縮関数を示します。

// 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;
}

追加または乗算する他の関数は、入力がこのライブラリ内の関数の 1 つによって作成されるため、入力が既に有効であると想定して作成する必要があります。質問とは関係がないため、コードは提供しません。

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

ユーザーが 以外の場所からデータを取得することを選択した場合は、データを検証するgetBinNum()ための呼び出しをユーザーに許可できます。checkBinNum()

あなたが本当に偏執的であるなら、ルーチンに渡されたすべての数値をチェックし、それに応じて行動する (NULL を返す) ことができますが、それには必要のない比較的高価なチェックが必要になります。

于 2009-03-23T07:12:24.453 に答える
0

文字列を整数に解析してから、整数に対して計算を実行する方が簡単ではないでしょうか?

これは学校の課題だと思いますが、あなたが頑張っているように見えるので、あなたに賛成です。

于 2009-03-23T05:25:07.550 に答える
-1

文字列が集合{0,1}の数字のみで構成されているという理由だけで、文字列が2進数であると仮定するのは危険です。たとえば、入力が「11」の場合、ユーザーは2進数で3ではなく、10進数で11を意味している可能性があります。恐ろしいバグを引き起こすのは、この種の不注意です。入力はあいまいに不完全であり、ユーザーがベースも指定するように実際に要求する必要があります。

于 2010-11-27T20:27:16.113 に答える