1

私は次のコードで非常に簡単なプログラミングエクササイズを完了しています:

    using System;

    namespace Factorial

{
    class MainClass
    {

        static int fives(int x) {

            int r = 0;
            while(x % 5 == 0) {
                r++;
                x /= 5;
            }
            return r;

        }

        static int z(int x) {

            if (x == 1)
                return 0;
            else
                return z (x-1) + fives (x);

        }

        public static void Main (string[] args)
        {
            int testCases = Convert.ToInt32 (Console.ReadLine ());
            int[] xs = new int[testCases];
            for (int i=0; i<testCases; i++)
                xs [i] = Convert.ToInt32 (Console.ReadLine ());
            foreach (int x in xs)
                Console.WriteLine (z (x));
        }
    }
}

少数でも問題なく動作するようですが、例の8735373では、「セグメンテーション違反:11」と出力されます。再帰が深くなりすぎてメモリが不足したということですか?何が原因ですか?

(私はMacのMono 2.10.8でC#を実行しています。)

PS:エクササイズ自体に興味がある人がいたら、これが私の最終的な解決策です(はるかに最適化されています)。

4

4 に答える 4

4

これは未処理のように見えますStackOverflowException- 再帰を使いすぎるとよくあることです。だから...再帰を使いすぎないでください。数学やいくつかの非常に特殊な言語 (おそらく F# で対応可能) では問題ないかもしれませんが、C# ではそうではありません。

それは次のようになります (検証されていません):

    static int z(int x)
    {
        int accumulator = 0;
        while(x!=1)
        {
            accumulator += fives(x);
            x--;
        }
        return accumulator;
    }

これはエラーになりません-再帰しません(fives反復ごとに呼び出しますが)。さらに良いことに、代数を実行して直接式を見つけます。

于 2012-05-29T21:48:25.777 に答える
2

より大きな数を使用すると、再帰ステップによって StackOverflowException が発生し、デバッガーを調べると、例外が発生した再帰ステップの数が表示されます。

Mono コードでは、Segmentaiton fault に対する stackoverflow 例外が何らかの形で考慮されていると思います。

ここに画像の説明を入力

必要に応じてデバッグできます: デバッガーなしで Ubuntu の Mono でセグメンテーション違反をデバッグするにはどうすればよいですか?

于 2012-05-29T21:55:40.587 に答える
1

問題の原因が大量の再帰である場合、エラーはおそらく StackOverflowException になります。golergka が前に述べたように、私はそれが Mono の障害であると確信しています。セグメンテーション違反は、到達すべきでないメモリ アドレスに到達しようとしてメモリが誤って管理されている場合に発生します。このタイプのエラーはシステム エラーです... C# の例外ではありません。私は、Mono が大量のメモリを適切に管理していないことはほぼ確実です。それがあなたの研究に役立つことを願っています。

于 2012-05-29T22:00:04.907 に答える
1

再帰からループへの単純な変換で問題が解決したようです。

    static int z (int x)
    {
        int result = 0;
        for (int i=1; i<=x; i++) {
            result += fives (i);
        }
        return result;
    }
于 2012-05-29T21:51:37.117 に答える