3

私は次の機能を持っています:

    public virtual long AsLong(object originalValue,long defaultValue)
    {
        double buffer = defaultValue;
        if (originalValue != null)
        {
            double result;
            var readValueIsconverted = double.TryParse(originalValue.ToString(), out result);
            if (readValueIsconverted)
                buffer = result;
        }

        var roundedValue = Math.Round(buffer, 0);
        var convertedValue = (long) roundedValue;
        return convertedValue;
    }

14.4 の変換を可能にするために double を使用しました! 次の失敗したテストがあります。

    [Fact]
    public void CanConvertLongMaxValue()
    {
        var cellValue = new Converter();
        const long longValue = 0x7FFFFFFFFFFFFFFF;
        var result = cellValue.AsLong(longValue, 12);

        Assert.Equal(longValue, result);

    } 

コードをトレースしたところ、roundedValue は正ですが、convertedValue は負です。それで、問題は何ですか?

4

3 に答える 3

4

double問題は、有効桁数が15 ~ 16の で、有効桁数が 19 桁 (10 進数) の整数値を保持しようとしていることです。

したがって、 で値を正確に表すことはできませんdouble。どうやら丸めにより、longに変換すると値がオーバーフローし、負の値になります。

これは次のように確認できます。

var convertedValue = checked((long)roundedValue);

このケースに絶対に対処する必要がある場合はdecimal、double の代わりに使用するか、小数点 (またはロケールで使用されているもの) で文字列を分割し、その方法で丸めを処理することをお勧めします。

于 2013-02-23T08:34:32.560 に答える
1

のタイプを確認してくださいoriginalValue。そのコンパイル時の型はですがobject、実行時の実際の型は何ですか?ボックス番号タイプの場合は、.ToString()その後に。を呼び出す必要はありませんTryParse。正しい型に直接箱を開けて(特にそれが常に同じ実行時型である場合)、必要に応じて別の数値型に変換することをお勧めします。

と同じlongように、多くの桁を含むを、を介して送信する場合、aは。よりも約10ビット高い精度を持っていることに注意してください。技術的には、aは指数に11ビットを使用しますが、最上位ビットを格納する必要がないためです。0x7FFFFFFFFFFFFFFFlong.MaxValuedoublelongdoubledouble

の値では、 2の累乗を渡すと指数が1上がるため、long.MaxValue精度が変化します。すぐ下の値の精度は1024です。これは、1024の倍数全体しか表現できないことを意味します。当然のことながら、すぐの値の精度は2048です。もちろん、整数型の精度は常に正確に1です。doubledoublelong.MaxValuedouble long.MaxValuelong

これが最も近い3つdoubleの下と上の3つlong.MaxValueです:

9.22337203685477'27'36 E+18
9.22337203685477'37'60 E+18
9.22337203685477'47'84 E+18
---
9.22337203685477'58'08 E+18  <-- two to the 63rd power
9.22337203685477'78'56 E+18
9.22337203685477'99'04 E+18

を変換するlong.MaxValueと、つまり、に変換9223372036854775807するdoubleと、最も近い表現可能な9.223372036854775808E+18ものは1.0大きすぎます。の文字列表現で.ToString()は15桁しか表示されませんが、 17桁(上記のリスト.ToString("R")のアポストロフィ)が表示されます。'double `9.223372036854775808E+18戻すと、数値が大きすぎるlongため、オーバーフロー例外が発生します。1.0もちろん、数値をに変換することもできulongます。これにより、正確な値が明らかになります。

于 2013-02-23T16:46:50.620 に答える
0

提供されたパラメーターがlong最初の場所にあるかどうかを確認する必要があります。

public virtual long AsLong(object originalValue,long defaultValue)
{
    if(originalValue.GetType() == typeof(long))
        return (long) originalValue;

    double buffer = defaultValue;

    ...
}

そうしないとlongdouble変換に関する情報が失われる可能性があります。

于 2013-02-23T08:37:26.487 に答える