36

TimeSpan.FromSecondsはdoubleを取り、100ナノ秒までの値を表すことができますが、この方法では、説明できないほど時間がミリ秒単位に丸められます。

この(文書化された!)動作を特定するために30分を費やしたばかりであることを考えると、なぜこれが当てはまるのかを知ることで、無駄な時間を我慢しやすくなります。

この一見逆効果の振る舞いが実装されている理由を誰かが提案できますか?

TimeSpan.FromSeconds(0.12345678).TotalSeconds
    // 0.123
TimeSpan.FromTicks((long)(TimeSpan.TicksPerSecond * 0.12345678)).TotalSeconds
    // 0.1234567
4

5 に答える 5

13

あなたが自分自身を知っているように、それは文書化された機能です。TimeSpanのドキュメントで説明されています:

パラメーター

タイプ:System.Double

ミリ秒単位で正確な秒数。

これはおそらく、doubleがそれほど正確ではないためです。ダブルスを比較するときは、予想よりも非常に小さいか小さい可能性があるため、常に丸めを行うことをお勧めします。この動作により、ミリ秒単位で入力しようとすると、実際には予期しないナノ秒が発生する可能性があります。これが、値をミリ秒単位に丸めて小さい桁を破棄することを選択した理由だと思います。

于 2011-01-21T19:44:36.957 に答える
7

憶測の権利について..

  1. TimeSpan.MaxValue.TotalMillisecondsは922337203685477に相当します。15桁の数字。
  2. double15桁まで正確です。
  3. TimeSpan.FromSecondsTimeSpan.FromMinutesなどはすべて、で表されるミリ秒に変換されますdouble(次に、ティックに変換されますが、TimeSpan現在は興味深いものではありません)

したがって、作成するときは、ミリ秒TimeSpanに近いTimeSpan.MaxValue(またはMinValue)変換が正確になります。 したがって、「なぜ」という質問に対する考えられる答えは、常に同じ精度持つことです。 さらに考えるべきことは、最初に値をで表されるティックに変換することによって変換が行われた場合、ジョブがより適切に実行された可能性があるかどうかです。

long

于 2011-01-21T14:50:38.670 に答える
5

あなたがTimeSpanタイプの設計を担当する開発者であると想像してください。すべての基本的な機能が整っています。それはすべてうまく機能しているようです。それからある日、ベータテスターがやって来て、このコードを表示します。

double x = 100000000000000;
double y = 0.5;
TimeSpan t1 = TimeSpan.FromMilliseconds(x + y);
TimeSpan t2 = TimeSpan.FromMilliseconds(x) + TimeSpan.FromMilliseconds(y);
Console.WriteLine(t1 == t2);

なぜその出力Falseですか?テスターがあなたに尋ねます。これが発生した理由(加算の精度の低下xと)を理解していても、クライアントの観点からは少し奇妙に見えるyことを認める必要があります。それから彼はあなたにこれを投げます:

x = 10.0;
y = 0.5;
t1 = TimeSpan.FromMilliseconds(x + y);
t2 = TimeSpan.FromMilliseconds(x) + TimeSpan.FromMilliseconds(y);
Console.WriteLine(t1 == t2);

その1つが出力しますTrueテスターは当然のことながら懐疑的です。

この時点で、決定を下す必要があります。値から構築された値間の算術演算を許可して、その精度が型自体の精度を超える結果を生成することもできます(たとえば、100000000000000.5(有効数字16桁))。または、許可しないこともできます。TimeSpandoubledouble

だからあなたは、あなたが何を知っているかを決定します、私はそれを作るだけで、aを使用してadoubleを構築するすべてのメソッドTimeSpanが最も近いミリ秒に丸められるようにします。このように、 aからaへの変換は損失の多い操作であり、クライアントがからに変換して正確な結果を期待した後にこのような奇妙な動作が見られる場合は、私を免除することが明示的に文書化されています。doubleTimeSpandoubleTimeSpan

私は、これがここでの「正しい」決定であると必ずしも主張しているわけではありません。明らかに、このアプローチはそれ自体でいくらかの混乱を引き起こします。どちらかの方法で決定を下す必要があると言っているだけで、これが明らかに決定されたものです。

于 2011-01-22T07:43:35.760 に答える
1

説明はそこにあると思います:TimeSpan構造は最小値と最大値に近い値を誤って処理します

そして、それはすぐに変わることはないようです:-)

于 2011-01-20T20:57:00.553 に答える
0

FromSecondsはプライベートメソッドIntervalを使用します

public static TimeSpan FromSeconds(double value)
{
    return Interval(value, 0x3e8);
}

0x3e8 == 1000

そのconstで値をmultiplayしてから、longにキャストする間隔メソッド(最後の行を参照):

private static TimeSpan Interval(double value, int scale)
{
    if (double.IsNaN(value))
    {
        throw new ArgumentException(Environment.GetResourceString("Arg_CannotBeNaN"));
    }
    double num = value * scale; // Multiply!!!!
    double num2 = num + ((value >= 0.0) ? 0.5 : -0.5);
    if ((num2 > 922337203685477) || (num2 < -922337203685477))
    {
        throw new OverflowException(Environment.GetResourceString("Overflow_TimeSpanTooLong"));
    }
    return new TimeSpan(((long) num2) * 0x2710L); // Cast to long!!!
}

その結果、3(x1000)の符号で精度が得られます。 リフレクターを使用して調査する

于 2011-01-21T05:11:05.830 に答える