C言語関係掲示板

過去ログ

No774 2進数の連続している1の最大の値を知りたい

[戻る] [ホームページ]
No.9561

2進数の連続している1の最大の値を知りたい
投稿者---真一(2003/10/04 22:56:16)


c言語はほとんど分かっていないのですが・・説明すると2進数で連続して1が続いている最大の値を調べたいんですが、
例えば、2進数で
    100111    という値なら最大値は3 
    101111011       最大値は4
    11111110000111  最大値は7
という風な感じです。
それを、例えば、5桁の最大値1は234個、最大値2は345個・・・という風にまとめるプログラムが欲しいのですが、(2進数で1桁から20桁まで調べたい)誰か心優しい方よろしくお願いします。(説明が悪くてすみません・・・)


No.9565

Re:2進数の連続している1の最大の値を知りたい
投稿者---RAPT(2003/10/05 00:07:33)


で、データはどのように格納されているのでしょうか?
char value[] = "10001111010111101011";
ってな感じでしょうか。それとも、
unsigned long num = 53;
とかいったものでしょうか。

以下、サンプル。VC++6sp5で動作確認済。

#include <stdio.h>

int main()
{
  const char value[] = "10011111010111101011";
  int count = sizeof(value) / sizeof(value[0]);  /* value[]の個数 */
  int max = 0;  /* 1の連続数の最大値 */
  int cur = 0;  /* 現在の1の連続数 */
  int i;  /* ループカウンタ */

  for(i = 0; i < count; ++i)
  {
    if (value[i] == '0')
    {
      if (max < cur)
      {
        /* もし、現在の連続数が最大値より大きければ、最大値を更新 */
        max = cur;
      }
      cur = 0;
    }
    else
    {
      ++cur;
    }
  }

  printf("2進数(%s)で1の連続する最大数は %d 個です。\n", value, max);
  return 0;
}


No.9567

Re:2進数の連続している1の最大の値を知りたい
投稿者---真一(2003/10/05 00:48:33)


本当にありがとうございます。感謝感謝。データの格納なんですがchar value[] = "10001111010111101011";のようにやっています。
あと、本当にすみませんが先ほどのプログラムを実行すると結果は2進数1001110101011で1の連続する最大数は 3 個です。というような答えが一つしか出ないのでしょうか?
 、20桁のような大きな桁になると(00000000000000000001〜111111111111111111111)約10万通りの1と0の組み合わせができると思うのですが、理想としては、最大連続数1は1234個最大連続数2は2345個・・・・・最大連続数19は2個最大連続数20は1個 のように一度にその桁の最大連続数のをすべて表示したいのですが・・・。



No.9569

Re:2進数の連続している1の最大の値を知りたい
投稿者---YuO(2003/10/05 02:04:33)


>あと、本当にすみませんが先ほどのプログラムを実行すると結果は2進数1001110101011で1の連続する最大数は 3 個です。というような答えが一つしか出ないのでしょうか?

一つ出せれば複数出せるようにすることは難しくないと思いますが。


> 、20桁のような大きな桁になると(00000000000000000001〜111111111111111111111)約10万通りの1と0の組み合わせができると思うのですが、理想としては、最大連続数1は1234個最大連続数2は2345個・・・・・最大連続数19は2個最大連続数20は1個 のように一度にその桁の最大連続数のをすべて表示したいのですが・・・。

20桁の組合せ(2^20=1024^2で約100万)すべてに対して呼び出して,
その結果をカウントすれば,その「理想」は実現可能です。

ただ,20桁の文字列を作っていくよりはunsigned long intを使って処理した方が,
よっぽど早い気がしますが……。

試しに作ったプログラムです。
内容は非常に素直な,
・0は読み飛ばす
・1は連続する数をカウントする
という内容のプログラムです。
int getMaxLength (unsigned long n)
{
    int r = 0;

    while (n != 0) {
        int count;

        while ((n & 1) == 0) n >>= 1;
        for (count = 0; (n & 1) == 1; ++count, n >>= 1);

        if (r < count) r = count;
    }

    return r;
}

これを2進数20桁の数値すべてに対してforで回すと,
0 : 1
1 : 17710
2 : 205606
3 : 324020
4 : 239231
5 : 133751
6 : 67249
7 : 32392
8 : 15309
9 : 7163
10 : 3328
11 : 1536
12 : 704
13 : 320
14 : 144
15 : 64
16 : 28
17 : 12
18 : 5
19 : 2
20 : 1
となりました。

アプローチとしては,他にN桁で連続する最大数がMbitの数をいきなり算出してしまう,
という方法もあります。
ただ,そちらは作るのが面倒そうです。
#処理系に型が存在しないビット数でも数えられるのが利点です。


No.9582

Re:2進数の連続している1の最大の値を知りたい
投稿者---真一(2003/10/05 09:55:09)


ありがとうございます。そのほかの桁も調べたかったのですが、なぜかうまくいきません・・・初心者のもので・・・すみません・・
 できれば先ほどの計算結果が出たプログラムをそのまま載せていただけないでしょうか?

No.9583

Re:2進数の連続している1の最大の値を知りたい
投稿者---YuO(2003/10/05 13:30:46)


> そのほかの桁も調べたかったのですが、なぜかうまくいきません・・・

デバッグしておかしな振る舞いは無かったのですか?
小さな数においてデバッガで追ってみれば,
この程度のプログラムなら問題なく原因追及ができると思いますが。
「うまくいかない」と言っているのに,
デバッガで調べておかしな振る舞いがないとは思えません。

そして,「うまくいかない」では何も情報を出していないのといっしょです。
・どのような環境において,
・どのようにプログラムを組んで
・どのような結果を期待して
・どのような結果が得られたか
を最低限の事項として記述して下さい。


> できれば先ほどの計算結果が出たプログラムをそのまま載せていただけないでしょうか?

単にループで0から2N-1まで回しただけですが。
プログラム自体は既に破棄しています。

No.9684

Re:2進数の連続している1の最大の値を知りたい
投稿者---mtk(2003/10/09 23:00:36)


>アプローチとしては,他にN桁で連続する最大数がMbitの数をいきなり算出してしまう,
>という方法もあります。
>ただ,そちらは作るのが面倒そうです。

そのアプローチで(自称)超高速なものが出来ました。(今度は確認済みです)
確かに作る前から、既に面倒でした。

#include <stdio.h>

#define N 20

unsigned long cnt[N+1];

unsigned long sig(int m, int n)
{
    unsigned long s = 0;

    if (m <= 1) return n;
    for (m--; n > 0; n--)
        s += sig(m, n);
    return s;
}

unsigned long comb(int m)
{
    unsigned long i, j;
    double f = 1;

    for (i = 0; i <= N; i++)
        if (cnt[1] == m) return 1;
    while (m > 1) f *= m--;
    for (i = 0; i <= N; i++)
        for (j = cnt[i]; j > 1; j--)
            f /= j;
    return (unsigned long)f;
}

unsigned long sum(int m, int n, int d)
{
    unsigned long s = 0;

    for (; d > 0; d--)
        if (n >= d) {
            cnt[d]++;
            s += sig(m + 1, n - d + 1) * comb(m + 1);
            s += sum(m + 1, n - d - 1, d);
            cnt[d]--;
        }
    return s;
}

int main(void)
{
    int i;

    printf(" 0: 1\n");
    for (i = 1; i <= N; i++) {
        cnt[i]++;
        printf("%2d: %lu\n", i, N-i+1 + sum(1, N - i - 1, i));
        cnt[i]--;
    }
    return 0;
}



No.9685

Re:2進数の連続している1の最大の値を知りたい
投稿者---mtk(2003/10/09 23:12:50)


訂正する部分がありました。

>    for (i = 0; i <= N; i++)
>        if (cnt[1] == m) return 1;

    for (i = 0; i <= N; i++)
        if (cnt[i] == m) return 1;

これに訂正します。

# この部分はオーバーフロー防止なので、N = 20 なら削除しても問題ないです。



No.9584

Re:2進数の連続している1の最大の値を知りたい
投稿者---mtk(2003/10/05 15:19:39)



なかなか高速なものが出来ました。

#include <stdio.h>

#define N 20

int main(void)
{
    int i, j, k, sum = 3, mask, count[N + 1] = { 1 }, end = 1<<N;

    for (i = 1; i < end; i++) {
        for (j = N/2 - 1; j > 0; j--) {
            mask = (1<<j) - 1;
            for (k = N + 1 - j; k > 0; k--) {
                if ((mask & i) == mask) {
                    count[j]++;
                    goto NEXT;
                }
                mask <<= 1;
            }
        }
        NEXT:
    }

    end = N / 2;
    count[N]   = 1;
    count[N-1] = 2;
    for (i = N - 2; i >= end; i--)
        sum += count[i] = count[i+1] * 2 + (1 << j++);
    count[i] -= sum;

    for (i = 0; i < N + 1; i++)
        printf("%2d : %d\n", i, count[i]);
    return 0;
}




No.9585

Re:2進数の連続している1の最大の値を知りたい
投稿者---mtk(2003/10/05 15:24:26)


>
>なかなか高速なものが出来ました。
>

やってしまいました。

最初の三重になっているループを抜けたら j が 0 になってるだろうと思って、
j = 0; を抜かしてしまいました。だから、追加してください。



No.9586

Re:2進数の連続している1の最大の値を知りたい
投稿者---mtk(2003/10/05 15:44:09)


N が奇数のときに、答えが合わなくなってました。

#include <stdio.h>

#define N 19

int main(void)
{
    int i, j, k, sum = 3, mask, count[N + 1] = { 1 }, end = 1<<N;

    for (i = 1; i < end; i++) {
        for (j = (N-1) / 2; j > 0; j--) {
            mask = (1<<j) - 1;
            for (k = N + 1 - j; k > 0; k--) {
                if ((mask & i) == mask) {
                    count[j]++;
                    goto NEXT;
                }
                mask <<= 1;
            }
        }
        NEXT:
    }

    end = (N-1) / 2;
    j = 0;
    count[N]   = 1;
    count[N-1] = 2;
    for (i = N - 2; i > end; i--)
        sum += count[i] = count[i+1] * 2 + (1 << j++);
    count[i] -= sum;

    for (i = 0; i < N + 1; i++)
        printf("%2d : %d\n", i, count[i]);
    return 0;
}



No.9587

Re:getcharについて
投稿者---mtk(2003/10/05 20:06:15)


gcc でコンパイルすると、NEXT ラベルが警告を言われました。
ということで

NEXT:

から

NEXT:;

へ訂正。

No.9588

Re:2進数の連続している1の最大の値を知りたい
投稿者---mtk(2003/10/05 20:10:37)


なぜかタイトルを変更してました。
(たぶん、クッキーというヤツ。(恥)


この投稿にコメントする

削除パスワード

No.9589

Re:2進数の連続している1の最大の値を知りたい
投稿者---かずま(2003/10/06 01:22:15)


> なかなか高速なものが出来ました。

本当に高速ですか?
YuO さんのプログラムを使ったほうが単純で倍ぐらい速いようですが。
#include <stdio.h>

int main(void)
{
    unsigned long count[21] = {0}, i, n, r, k;

    for (i = 0x00000; i <= 0xFFFFF; i++) {
         r = 0,  n = i;
         while (n != 0) {
             while ((n & 1) == 0) n >>= 1;
             for (k = 0; n & 1; n >>= 1) k++;
             if (k > r) r = k;
         }
         count[r]++;
    }
    for (i = 0; i <= 20; i++) printf("%3lu: %lu\n", i, count[i]);
    return 0;
}


No.9595

Re:2進数の連続している1の最大の値を知りたい
投稿者---mtk(2003/10/06 21:07:16)


>本当に高速ですか?
>YuO さんのプログラムを使ったほうが単純で倍ぐらい速いようですが。

確認もせずに、高速と言ってしまいました。
確かに、倍ぐらい速かったです。

かなり、すみませんでした。(皆さん)

No.9598

Re:2進数の連続している1の最大の値を知りたい
投稿者---aki(2003/10/07 02:56:21)


なかなか高速なものが出来ました。

#include <stdio.h>

int main(void)
{
    long i, x, b, count[20+1] = {0};

    for (i = 0; i < 0x100000; i++) {
        x = i;
        for (b = 0; x; b++)
            x &= x << 1;
        count[b]++;
    }

    for (b = 0; b <= 20; b++)
        printf("%2ld: %ld\n", b, count[b]);
    return 0;
}