web-dev-qa-db-ja.com

C#で10進データ型に対して数学演算を実行しますか?

上記は可能かと思っていました。例えば:

Math.Sqrt(myVariableHere);

オーバーロードを見ると、doubleパラメーターが必要なので、10進数のデータ型でこれを複製する別の方法があるかどうかはわかりません。

19
Qcom

decimal(通貨など)が関係するほとんどの場合、ルートを取ることは便利ではありません。また、ルートには、decimalに期待されるような期待される精度はありません。もちろん、キャストすることで強制することができます(decimal範囲の極端な端を扱っていないと仮定します):

decimal root = (decimal)Math.Sqrt((double)myVariableHere);

これにより、少なくとも固有の丸めの問題を認識する必要があります。

4
Marc Gravell

その質問に対するすべての答えが同じである理由がわかりません。

数値から平方根を計算する方法はいくつかあります。それらの1つはアイザックニュートンによって提案されました。このメソッドの最も単純な実装の1つだけを記述します。ダブルの平方根の精度を上げるために使用します。

// x - a number, from which we need to calculate the square root
// epsilon - an accuracy of calculation of the root from our number.
// The result of the calculations will differ from an actual value
// of the root on less than epslion.
public static decimal Sqrt(decimal x, decimal epsilon = 0.0M)
{
    if (x < 0) throw new OverflowException("Cannot calculate square root from a negative number");

    decimal current = (decimal)Math.Sqrt((double)x), previous;
    do
    {
        previous = current;
        if (previous == 0.0M) return 0;
        current = (previous + x / previous) / 2;
    }
    while (Math.Abs(previous - current) > epsilon);
    return current;
}

速度について:最悪の場合(epsilon = 0、数値はdecimal.MaxValue)、ループの繰り返しは3回未満です。

詳細を知りたい場合は、 this(Hacker's Delightby Henry S. Warren、Jr。) をお読みください。

52
SLenik

私はちょうどこの質問に出くわしました、そして私はSLenikが提案したものとは異なるアルゴリズムを提案したいと思います。これは バビロニア法 に基づいています。

public static decimal Sqrt(decimal x, decimal? guess = null)
{
    var ourGuess = guess.GetValueOrDefault(x / 2m);
    var result = x / ourGuess;
    var average = (ourGuess + result) / 2m;

    if (average == ourGuess) // This checks for the maximum precision possible with a decimal.
        return average;
    else
        return Sqrt(x, average);
}

既存のSqrt関数を使用する必要がないため、doubleへの変換とその逆の変換が回避され、精度が低下します。

4
Bobson