LoginSignup
kisara11235
@kisara11235

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

2進法ビットの保存

Q&AClosed

解決したいこと

二進法を用いてケットを表現し、そのケットを別の配列で保存したい
今回はケットの中に2個だけ1が入るように設定している。

発生している問題・エラー

000
000
000

コンパイルはうまくいき、実際ケットは2個1が入っており、逆引きもうまく行っているように思える。が、ケットの保存がうまく行っていない

該当するソースコード

#include <stdio.h>

#define N  3  //サイト数
#define M  2  //half-filling
#define NUM_KET  N*(N-1)/2 
    
// ケットベクトルを2進法で保存する配列
int binaryKet[N];
int ket[NUM_KET][N];

// 2進数を10進数に変換する関数
int binaryToDecimal(int* binaryKet, int n) {
    int decimal = 0;
    for (int i = 0; i < n; i++) {
        decimal = (decimal << 1) | binaryKet[i];
    }
    return decimal;
}
// 10進法から2進法のケットベクトルを取得
void DecimaltTobinary(int n, int decimalKet, int* binaryKet){
    for (int i = n - 1; i >= 0; i--) {
        binaryKet[i] = decimalKet & 1;
        decimalKet >>= 1;
    }
}

// ケットベクトルを2進法で配列に保存する関数
void getBinaryKet(int n, int ones, int* binaryKet, int index, int z) {
    if (ones == 0) {
        // 2つの1が配置されたケットベクトルを表示
        for (int i = 0; i < n; i++) {
            // printf("%d", binaryKet[i]);
            ket[z][i]=binaryKet[i];
        }
        // printf(" (%d)\n", binaryToDecimal(binaryKet, n));
        // printf("\n");
        return;
    }

    if (index >= n) {
        return;
    }

    // 1を配置する場合
    binaryKet[index] = 1;
    getBinaryKet(n, ones - 1, binaryKet, index + 1, z);

    // 0を配置する場合
    binaryKet[index] = 0;
    getBinaryKet(n, ones, binaryKet, index + 1, z);
}

int main() {
    int ones = M; // 1の個数

    // ケットベクトルの生成と表示
    // printf("Generated ket vectors:\n");
    // getBinaryKet(N, M, binaryKet, 0);

    int z=0;
    while(z < NUM_KET){
        getBinaryKet(N, M, binaryKet, 0,z);
        z++;
    }
    for(int i=0;i<NUM_KET;i++){
        for(int j=0;j<N;j++){
            printf("%d",ket[i][j]);
        }
        printf("\n");
    }

    // 逆引きを行う例
    int decimalKet = 5; // 10進法で指定するケットベクトル (例: 5は0101に対応)

    DecimaltTobinary(N, decimalKet, binaryKet);

    // 逆引き結果を表示
    printf("Decimal: %d (Binary): ", decimalKet);
    for (int i = 0; i < N; i++) {
        printf("%d", binaryKet[i]);
    }
    printf("\n");

    return 0;
}


自分で試したこと

0

2Answer

ケットという用語に聞き馴染みが無いのでよく分かっていませんが、
上のプログラムを実行すると、以下の内容が出力されました。

011
011
011
Decimal: 5 (Binary): 101

また、実行が終わった時の変数は以下の値でした。

binaryKet[0]: 1
binaryKet[1]: 0
binaryKet[2]: 1
ket[0][0]: 0
ket[0][1]: 1
ket[0][2]: 1
ket[1][0]: 0
ket[1][1]: 1
ket[1][2]: 1
ket[2][0]: 0
ket[2][1]: 1
ket[2][2]: 1

ケットの保存がうまく行っていない

どこが期待と違う内容(値)でしょうか?

0

Comments

  1. @kisara11235

    Questioner

    ケットはベクトルの事だと思って貰えると幸いです。
    期待する値としては3桁の二進法でふたつの1を入れるプログラムを書いているので、
    110
    101
    011
    の3つが計算されます。getbinaryketの関数で表示した場合、この3つが正しく出るのですが、このベクトルをketに移す際に
    011
    011
    011
    しか出ていないのが現状です。
    原因としては再帰呼び出しで最後の011のみが配列に入っているようで、ここを解決したいです。
    言葉足らずで申し訳ございません。

  2. getbinaryketを再帰で呼び出していて、z=0のとき、110101011を生成しています。
    z=1のときも、110101011を生成していて、z=2も同様。
    なので、最終的にketには、それぞれの最後に生成された011が格納されることになります。
    プログラム通りの結果です。

    もし、z=0のとき110z=1のとき101z=2のとき011を期待されていたのなら、mainの中のwhile(z < NUM_KET)ループは不要で、getBinaryKetの中のif (ones == 0)の最後にzをインクリメントするようにすれば良いと思います。


    zが引数で、更新しても意味が無いので、メインのループは残して、再帰を止めるのが良いですね。

  3. 再帰を止めるスマートな方法が思い浮かばなかったので、zをポインタで渡して更新できるようにしてみました。

    出力結果
    110
    101
    011
    Decimal: 5 (Binary): 101
    
    ⭐️印:変更箇所
    #include <stdio.h>
    
    #define N  3  //サイト数
    #define M  2  //half-filling
    #define NUM_KET  N*(N-1)/2 
        
    // ケットベクトルを2進法で保存する配列
    int binaryKet[N];
    int ket[NUM_KET][N];
    
    // 2進数を10進数に変換する関数
    int binaryToDecimal(int* binaryKet, int n) {
        int decimal = 0;
        for (int i = 0; i < n; i++) {
            decimal = (decimal << 1) | binaryKet[i];
        }
        return decimal;
    }
    // 10進法から2進法のケットベクトルを取得
    void DecimaltTobinary(int n, int decimalKet, int* binaryKet){
        for (int i = n - 1; i >= 0; i--) {
            binaryKet[i] = decimalKet & 1;
            decimalKet >>= 1;
        }
    }
    
    // ケットベクトルを2進法で配列に保存する関数
    void getBinaryKet(int n, int ones, int* binaryKet, int index, int* z) { //⭐️
        if (ones == 0) {
            // 2つの1が配置されたケットベクトルを表示
            for (int i = 0; i < n; i++) {
                // printf("%d", binaryKet[i]);
                ket[*z][i]=binaryKet[I]; //⭐️
            }
            // printf(" (%d)\n", binaryToDecimal(binaryKet, n));
            // printf("\n");
            (*z)++; //⭐️
            return;
        }
    
        if (index >= n) {
            return;
        }
    
        // 1を配置する場合
        binaryKet[index] = 1;
        getBinaryKet(n, ones - 1, binaryKet, index + 1, z);
    
        // 0を配置する場合
        binaryKet[index] = 0;
        getBinaryKet(n, ones, binaryKet, index + 1, z);
    }
    
    int main() {
        int ones = M; // 1の個数
    
        // ケットベクトルの生成と表示
        // printf("Generated ket vectors:\n");
        // getBinaryKet(N, M, binaryKet, 0);
    
        int z=0;
    //  while(z < NUM_KET){ //⭐️
            getBinaryKet(N, M, binaryKet, 0, &z); //⭐️
    //      z++; //⭐️
    //  } //⭐️
        for(int i=0;i<NUM_KET;i++){
            for(int j=0;j<N;j++){
                printf("%d",ket[i][j]);
            }
            printf("\n");
        }
    
        // 逆引きを行う例
        int decimalKet = 5; // 10進法で指定するケットベクトル (例: 5は0101に対応)
    
        DecimaltTobinary(N, decimalKet, binaryKet);
    
        // 逆引き結果を表示
        printf("Decimal: %d (Binary): ", decimalKet);
        for (int i = 0; i < N; i++) {
            printf("%d", binaryKet[i]);
        }
        printf("\n");
    
        return 0;
    }
    
  4. @kisara11235

    Questioner

    返信遅れて申し訳ございません。コンパイルしたとことまさに僕がほしい結果となりました。
    本当にありがとうございます。
    zのループや再帰呼び出しについては理解していたのですが、なぜポインタを用いるとうまく行くのでしょうか。

@nak435 さんのポインタ変数を使っているコードですが、グローバル変数ketと同様にインデックス変数もグローバル変数にすればポインタ変数不要にできますね。

#include <stdio.h>

#define N (3)  // サイト数
#define M (2)  // half-filling
#define NUM_KET (N *(N - 1) / 2)

// ケットベクトルを2進法で保存する配列
int ket[NUM_KET][N];
int ket_index = 0;

void addKet(int *binary, int length) {
    for (int i = 0; i < length; i++) {
        ket[ket_index][i] = binary[i];
    }
    ket_index++;
}

int binaryToDecimal(int *binary, int length) {
    int decimal = 0;
    for (int i = 0; i < length; i++) {
        decimal = (decimal << 1) | binary[i];
    }
    return decimal;
}

void decimalToBinary(int decimal, int *binary, int length) {
    for (int i = length - 1; i >= 0; i--) {
        binary[i] = decimal & 1;
        decimal >>= 1;
    }
}

int printBinary(int *binary, int length) {
    for (int i = 0; i < length; i++) {
        printf("%d", binary[i]);
    }
    printf("\n");
}

// ケットベクトルを2進法でket配列に保存する関数
void fillKet(int ones, int *binary, int binary_length, int binary_index) {
    if (ket_index >= NUM_KET) {
        return;
    }

    if (binary_index >= binary_length) {
        return;
    }

    if (ones > 0) {
        // 1を配置してみる
        binary[binary_index] = 1;
        fillKet(ones - 1, binary, binary_length, binary_index + 1);
        if (ones - 1 == 0) {
            // onesの分だけ1が埋まったのでketに追加保存
            addKet(binary, binary_length);
        }
    }

    // 0を配置してみる (onesが0でも残りの桁を0で埋める必要がある)
    binary[binary_index] = 0;
    fillKet(ones, binary, binary_length, binary_index + 1);
}

int main() {
    int binary[N];
    int ones = M; // 1の個数

    // ケットベクトルの生成と表示
    // printf("Generated ket vectors:\n");
    fillKet(ones, binary, N, 0);

    for (int i = 0; i < NUM_KET; i++) {
        printBinary(ket[i], N);
    }

    return 0;
}
0

Your answer might help someone💌