【解決方法】最大公約数 (GCD) を見つける方法

プログラミングQA


C++ についてサポートが必要です。
最大公約数を見つける 𝑔𝑐𝑑⁡(𝑎,𝑏) 2 つの正の整数の間 𝑎 そして 𝑏
例:

a = 20230925 b = 52903202
a = 111111222222333333444444555555 b = 666666777777888888999999

コードは Visual Studio の Linux および Windows 上で動作するはずですが、エラーが発生します。

私が試したこと:

C++
#include <iostream>
#include <string>
#include <vector>

int num_cmp(const std::vector<int>& num1, const std::vector<int>& num2){
    std::cout << "num_cmp\n";
    /* function comparing two numbers whose digits are stored in vectors
    return -1 if smaller, 1 if larger, and 0 if equal */

    // compare number of digits first
    int len1 = num1.size(), len2 = num2.size();
    int msb = 0;
    while (num1[msb] == 0){  // skip zeros
        -- len1;
        ++ msb;
    }
    msb = 0;
    while (num2[msb] == 0){  // skip zeros
        -- len2;
        ++ msb;
    }
    if (len1 > len2)
        return 1;
    else if (len1 < len2)
        return -1;
    else {
        // if same length, compare digit by digit
        for (int i = 0; i < len1; ++i){
            if (num1[i] > num2[i])
                return 1;
            else if (num1[i] < num2[i])
                return -1;
        }
    }
    return 0;
}

void vec_intfromchar(std::vector<int>& a, const std::vector<char>& num) {
	/* convert char vector to int vector
	 two vectors are assumed to have the same size  */
	a.resize(num.size()); // Asegura que a tenga el mismo tamaño que num
	for (int i = 0; i < a.size(); ++i)
		a[i] = num[i] - '0';
	return;
}

void print_vec(std::vector<int>& a){
    int start = 0;
    while (start < a.size() && a[start ++] == 0); // skip zeros
    for (int i = start - 1; i < a.size(); ++i)
        std::cout << a[i];
    std::cout << "\n";

    return;
}

bool is_even(std::vector<int>& a){
    std::cout << "is_even\n";
    return a[a.size() - 1] % 2 == 0;
}

bool is_zero(std::vector<int>& a){
    std::cout << "is_zero\n";
    for (int i = 0; i < a.size(); ++i)
        if (a[i] != 0)
            return false;
    return true;
}

void substract(std::vector<int>& b, std::vector<int>& a){
    std::cout << "============ subtract =============\n";
    // b = b - a
    while (a.size() < b.size())
        a.insert(a.begin(), 0); // sign extension
    while (a.size() > b.size())
        b.insert(b.begin(), 0); // sign extension
    print_vec(a);
    print_vec(b);

    for (int i = b.size() - 1; i >= 0; --i){
        // std::cout << "b[" << i << "]: " << b[i] << ", a[" << i << "]: " << a[i] << "\n";
        if (b[i] < a[i]){
            b[i] = b[i] - a[i] + 10;
            -- b[i - 1];  // borrow
        }
        else
            b[i] -= a[i];
    }
    return;
}

void divide_by2(std::vector<int>& a) {
	std::cout << "divide_by2\n";
	int dividend = 0;
	for (int i = 0; i < a.size(); ++i) {
		dividend = dividend * 10 + a[i];
		a[i] = dividend / 2;
		dividend %= 2;
	}
    return;
}

void multiply_by2(std::vector<int>& a){
    std::cout << "multiply_by2\n";
    int mult = 0, carry = 0;
    for (int i = a.size() - 1; i >= 0; --i){
        mult = a[i] * 2 + carry;
        carry = mult / 10;
        a[i] = mult % 10;
    }
    return;
}

void addition(std::vector<int>& a, std::vector<int>& b){
    std::cout << "addtion\n";
    // a = a + b

    while (a.size() < b.size())
        a.insert(a.begin(), 0); // sign extension
    while (b.size() < a.size())
        b.insert(b.begin(), 0); // sign extension

    int add = 0, carry = 0;
    for (int i = a.size() - 1; i >= 0; --i){
        add = a[i] + b[i] + carry;
        carry = add / 10;
        a[i] = add % 10;
    }
    return;
}

std::vector<int> multiply(std::vector<int>& a, std::vector<int>& b){
    std::cout << "multiply\n";

    std::vector<int> acc(a.size() + b.size(), 0); // the final result

    for (int i = b.size() - 1; i >= 0; --i){
        int mult = 0, carry = 0;
        std::vector<int> result(a.size() + 1, 0);   // middle result

        for (int j = a.size() - 1; j >= 0; --j){
            mult = a[j] * b[i] + carry;
            carry = mult / 10;
            // std::cout << "mult: " << mult << "\n";
            // std::cout << "carry: " << carry << "\n";
            result[j + 1] = mult % 10;
            if (j == 0)
                result[0] = carry;
        }

        // std::cout << "result: ";
         print_vec(result);

        // append zeros to the oprand
        for (int k = i + 1; k < b.size(); ++k)
            result.insert(result.end(), 0);
        // std::cout << "result after appending: ";
         print_vec(result);

        // acumulation
        addition(acc, result);
        // std::cout << "acc: ";
         print_vec(acc);
    }
    return acc;
}

int main(){
    std::string str1, str2;
    std::cin >> str1 >> str2;
    std::vector<char> num1(str1.begin(), str1.end());
    std::vector<char> num2(str2.begin(), str2.end());
    
    // initial values for a, b, and ans
    std::vector<int> ans(1, 1);
    std::vector<int> a(num1.size());
    std::vector<int> b(num2.size());
    vec_intfromchar(a, num1);
    vec_intfromchar(b, num2);

    // std::cout << num_cmp(a, b) << "\n";
    if (num_cmp(a, b) != -1)
        a.swap(b);  // set a to be the smaller one
    
    // Binary Algorithm for gcd
    while (!is_zero(a) && !is_zero(b)){
        if (is_even(a) && is_even(b)) {
            multiply_by2(ans);
            divide_by2(a);
            divide_by2(b);
        } else if (is_even(a)) {
            divide_by2(a);
        } else if (is_even(b)) {
            divide_by2(b);
        }

        if (num_cmp(a, b) == 1)  // a > b
            a.swap(b);
        substract(b, a);    // b = b - a
    }
    std::vector<int> gcd = multiply(a, ans);
  /*  print_vec(gcd);*/

    return 0;
}

解決策 1

つまり…コメントも文書化もされていない、ユーザーにとって不親切なコードが 200 行以上あり、入力しやすく、読みにくいようにできるだけ短い変数名が満載されています。

そして、あなたが私たちに言うのは「エラーが発生する」だけです…

コンパイルしたからといって、コードが正しいというわけではありません。
開発プロセスを電子メールを書くことと考えてください。コンパイルが成功したということは、電子メールを適切な言語 (たとえばドイツ語ではなく英語) で書いたことを意味します。電子メールに送信したいメッセージが含まれていたわけではありません。

これで、開発の第 2 段階 (実際には第 4 段階か第 5 段階ですが、後で初期段階に戻ります) に入ります: テストとデバッグ。

まず、それが何をするのか、そしてそれがあなたが望んでいることとどう違うのかを見てみましょう。 これは、なぜそのような動作をしているのかについての情報を提供するため、重要です。 たとえば、プログラムがユーザーに数値を入力させ、その数値を 2 倍にして答えを出力することを目的としている場合、入力/出力が次のようになったとします。

Input   Expected output    Actual output
  1            2                 1
  2            4                 4
  3            6                 9
  4            8                16

次に、問題はそれを 2 倍にするビットにあることは明らかです。ビット自体に加算したり 2 を乗算したりするのではなく、自身を乗算して入力の 2 乗を返します。
それで、コードを見ると、それがここのどこかにあることが明らかです。

C++
int Double(int value)
   {
   return value * value;
   }

何が問題なのかがわかったら、デバッガーを使用してその理由を調べてください。 メソッドの最初の行にブレークポイントを配置し、アプリを実行します。 ブレークポイントに到達すると、デバッガーは停止し、制御がユーザーに渡されます。 コードを 1 行ずつ実行し (「シングル ステップ」と呼ばれます)、必要に応じて変数の内容を確認 (または変更) できるようになりました (必要に応じて、コードを変更して再試行することもできます)。
コードを実行する前にコードの各行が何をすべきかを考え、それを「ステップオーバー」ボタンを使用して各行を順番に実行したときの実際の動作と比較してください。 期待通りの結果になりましたか? その場合は、次の行に進みます。
そうでない場合は、なぜそうではないのでしょうか? どう違うのでしょうか?
コードのどの部分に問題があるのか​​、また何が問題なのかを特定するのに役立つことを願っています。
これはスキルであり、開発だけでなく現実世界でも役立つため、伸ばす価値のあるスキルです。 すべてのスキルと同様、それは使用することでのみ向上します。

コメント

タイトルとURLをコピーしました