2

「s」と呼ばれるこの元の C++ 関数があります。

long s(long n) {
  long sum = 0;
  long m;

  m = (long) sqrt(n);
  for (long i = 2; i < m; i++)
    if ((n % i) == 0) sum += (i + (n/i));
  if (n>1) sum += 1;
  if ((m*m) == n) sum += m;
  return sum;
}

この関数を GMP の mpz 型を使用するように変換して、任意の長さの整数を使用できるようにするのに苦労してきました。

これは私の試みです:

void s(mpz_t n, mpz_t *final)
{
    mpz_t sum;
    mpz_t m;
    mpz_t temp;

    mpz_init (sum);
    mpz_init (m);
    mpz_init (temp);

    mpz_set_str (sum, "0", 10);

    mpz_sqrt(m, n);
    for (mpz_t i, mpz_init(i), mpz_set_str(i, "2", 10); mpz_cmp(i,m)< 0; mpz_add_ui(i, i, 1))
    {
        mpz_mod(temp, n, i);
        if (mpz_cmp_si(temp, 0) == 0)
        {
            // use divexact since we know they are divisable
            mpz_divexact(temp, n, i);
            mpz_add(temp, temp, i);
            mpz_add(sum, sum, temp);
        }
    }

    if (mpz_cmp_si(n, 1) > 0) mpz_add_ui(sum, sum, 1);

    mpz_mul(temp, m, m);
    if (mpz_cmp(temp, n) == 0) mpz_add(sum, sum, m);
    final = sum;
}

元のプログラム全体はここにあります: http://pastebin.com/mf751592

私は何を間違っていますか?型 mpz_t を返すことができなかったので、最初は問題があったようです。その代わりに、関数が返すものへのポインターを渡しました。

私はまだそれに苦労しています。誰かが私を正しい方向に向けることができますか?

この行:次の for (mpz_t i, mpz_init(i), mpz_set_str(i, "2", 10); mpz_cmp(i,m)< 0; mpz_add_ui(i, i, 1))
エラーが表示されます: 23: エラー: この構文を使用して配列を初期化できません

4

5 に答える 5

3

あなたはほとんど正しい軌道に乗っていました。ただし、両方の関数パラメーターは mpz_t 型である必要があります。したがって、ヘッダーは次のようになります。

void s(mpz_t n, mpz_t final)

最後に final = sum は必要ありません。代わりに、sum を使用するすべての場所で final を使用してください。また、次のことを行います。

mpz_t i;
for (mpz_init_set_ui(i, 2); mpz_cmp(i,m) < 0; mpz_add_ui(i, i, 1))

forループのために。呼び出しは次のようになります。

mpz_t final, n;
mpz_init(final);
mpz_init_set_ui(n, 5);
s(n, final);

編集: Steve314 が指摘したように、すべての mpz_init に対して mpz_clear を実行する必要があります。発信者に initted final を渡すことができるので、m、temp、および i をクリーンアップする必要があります。

于 2010-02-13T22:59:52.233 に答える
1

gmp は純粋な C ライブラリ、IIRC です。

mpz_t 変数のクリーンアップの欠如 (C にはデストラクタがない)、および最後の行での代入演算子の使用 (C にはオーバーロードされた演算子がない - これは事実上 POD memcpy です) が懸念される領域です。IIRC、mpz_clear は整数クリーンアップ関数です。

代入を mpz_set または mpz_swap のいずれかに置き換えます - 基礎となるデータ構造のコピーを回避するため、一時を削除しようとしている場合はスワップがより効率的です。

それでも、実際に説明できるのはメモリリークだけです。

私の次の疑惑の領域は、同じ変数が入力と出力の両方として使用される呼び出しです。gmp についてはわかりませんが、ポインターを渡すときに多くのライブラリがこれを好まないため、使用中に入力パラメーターが変更され (出力でもあるため)、破損が発生します。追加のテンポラリがいくつか必要になる場合があります。

于 2010-02-13T23:06:02.277 に答える
1

代わりに for ループの前に i を宣言して初期化するだけです..

mpz_t i;
mpz_init(i);
mpz_set_str(i, "2", 10);

for (; mpz_cmp(i,m)< 0; mpz_add_ui(i, i, 1)) {
   ...
}
于 2010-02-13T23:02:06.323 に答える
1

最後の行は *final = sum; にする必要があります。それ以外の場合は、ポインターが指すアドレスを変更します。

または、代わりに参照を使用してください:)

于 2010-02-13T22:50:36.887 に答える
0

テンプレートを使ってみる

template <class myType>
myType s(myTypen) {
myType sum = 0;
myType m;

m = (myType) sqrt(n);
for (myType i = 2; i < m; i++)
  if ((n % i) == 0) sum += (i + (n/i));
 if (n>1) sum += 1;
if ((m*m) == n) sum += m;
return sum;
}
于 2010-02-13T22:50:25.653 に答える