projecteuler.net の問題を解決しようとしていますが、いくつかの問題が発生しています。
最初の問題は、大量の要素をList<t>
に格納することです。リストに大量に保存するとOutOfMemoryExceptionが発生し続けます。
私はこれらのことを最善の方法で行っていない可能性があることを認めましたが、アプリが消費できるメモリの量を定義する方法はありますか?
通常、約100,000,000の要素を取得するとクラッシュします。
第二に、いくつかの質問は膨大な数の追加を必要とします。数値が非常に大きくなると思われる場所でulongデータ型を使用していますが、サポートされている最大のintを折り返して負の数値に入れることができます。
信じられないほど大きな数を処理するためのヒントはありますか?
System.Numerics.BigInteger を検討してください。
これらの演算を分割するには、いくつかの基本的な数学プリンシパルを使用する多数のクラスを使用する必要があります。 CodePojectでの C#BigIntegerライブラリの実装 は、最も有望なようです。この記事では、膨大な数の操作がどのように機能するかについても説明しています。
以下も参照してください。 C#の大きな整数
プロジェクトオイラーに関する限り、OutOfMemory例外が発生した場合、間違ったツリーが表示される可能性があります。彼らのウェブサイトから:
各問題は「1分間のルール」に従って設計されています。つまり、より困難な問題を含むアルゴリズムを成功させるには数時間かかる場合がありますが、効率的な実装により、 1分未満。
ユーザーJakersが言ったように、もしあなたがBig Numbersを使っているなら、おそらくそれは間違っているでしょう。
これまでに行ったProjectEulerの問題のうち、これまで大規模な計算を必要としたものはありませんでした。大きな数を避けるための適切なアルゴリズムを見つけることについての詳細です。
ヒントが必要ですか?ここに投稿してください。興味深いオイラースレッドが開始される可能性があります。
これはC#だと思いますか? F#には、これらの問題(BigInt型と遅延シーケンス)の両方を処理する方法が組み込まれています。
必要に応じて、C#の両方のF#テクニックを使用できます。 BigInt型は、コアF#アセンブリへの参照を追加する場合、他の言語から合理的に使用できます。
レイジーシーケンスは、基本的に構文に適した列挙子です。リストに1億個の要素を配置することは良い計画ではないので、それを回避するためにソリューションを再考する必要があります。情報を保持する必要がない場合は、捨ててください。保存するよりも再計算する方が安ければ、捨ててください!
この thread の回答を参照してください。おそらく、使用可能なサードパーティのビッグ整数ライブラリ/クラスの1つを使用するか、ネイティブのBigIntegerデータ型を含むC#4.0を待つ必要があります。
BigIntegerを使用する必要はありません。このイベントは数値の文字列配列で実行できます。
class Solution
{
static void Main(String[] args)
{
int n = 5;
string[] unsorted = new string[6] { "3141592653589793238","1", "3", "5737362592653589793238", "3", "5" };
string[] result = SortStrings(n, unsorted);
foreach (string s in result)
Console.WriteLine(s);
Console.ReadLine();
}
static string[] SortStrings(int size, string[] arr)
{
Array.Sort(arr, (left, right) =>
{
if (left.Length != right.Length)
return left.Length - right.Length;
return left.CompareTo(right);
});
return arr;
}
}
アプリが使用するメモリの量を定義する限り、 MemoryFailPoint クラスを使用して、操作を実行する前に使用可能なメモリを確認できます。
これにより、操作を実行する前にメモリを事前に割り当てることができるため、操作を実行する前に操作が失敗するかどうかを確認できます。
それを処理する良い方法であるかどうかはわかりませんが、私のプロジェクトでは以下を使用しています。
各項目に「double theRelevantNumber」変数と「int PowerOfTen」があり、関連するクラスに「int relatedDecimals」変数があります。
ですから...大きな数に遭遇すると、次のように処理されます。
最初に、それらはx、yyy形式に変更されます。したがって、123456,789の数値が入力され、「powerOfTen」が10の場合、次のように始まります。
theRelevantNumber = 123456,789 PowerOfTen = 10その数は123456,789 * 10 ^ 10でした。
次に、1,23456789 * 10 ^ 15に変更されます。
次に、関連する小数の数(たとえば5)で1,23456に丸められ、「PowerOfTen = 15」とともに保存されます。
数値を加算または減算する場合、関連する小数点以下の数値は無視されます。あなたが取る場合の意味:
1 * 10 ^ 15 + 1 * 10 ^ 10「relevantDecimals」が5の場合は1,00001に変更されますが、「relevantDecimals」が4の場合はまったく変更されません。
このメソッドを使用すると、doubleLimit * 10 ^ intLimitまでの数値を問題なく処理できます。少なくともOOPの場合)、追跡するのはそれほど難しくありません。
string Add(string s1, string s2)
{
bool carry = false;
string result = string.Empty;
if (s1.Length < s2.Length)
s1 = s1.PadLeft(s2.Length, '0');
if(s2.Length < s1.Length)
s2 = s2.PadLeft(s1.Length, '0');
for(int i = s1.Length-1; i >= 0; i--)
{
var augend = Convert.ToInt64(s1.Substring(i,1));
var addend = Convert.ToInt64(s2.Substring(i,1));
var sum = augend + addend;
sum += (carry ? 1 : 0);
carry = false;
if(sum > 9)
{
carry = true;
sum -= 10;
}
result = sum.ToString() + result;
}
if(carry)
{
result = "1" + result;
}
return result;
}