34 votes

Pourquoi TimeSpan.FromSeconds (double) arrondit-il en millisecondes?

TimeSpan.FromSeconds prend un double et peut représenter des valeurs jusqu'à 100 nanosecondes, mais cette méthode arrondit inexplicablement le temps à des millisecondes entières.

Étant donné que je viens de passer une demi-heure à identifier ce comportement (documenté!), Savoir pourquoi cela pourrait être le cas faciliterait la gestion du temps perdu.

Quelqu'un peut-il suggérer pourquoi ce comportement apparemment contre-productif est mis en œuvre?

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

11voto

GolezTrol Points 54531

Comme vous l'avez constaté vous-même, c'est une fonctionnalité documentée. Il est décrit dans la documentation de la plage de Temps:

Paramètres

valeur Type: System.Double

Un certain nombre de secondes, précis à la milliseconde la plus proche.

La raison pour cela est probablement parce que le double n'est pas exacte. C'est toujours une bonne idée de faire un peu d'arrondi lorsque l'on compare les doubles, parce que c'est peut-être juste un tout petit peu plus grand ou plus petit que ce que vous attendez. Ce comportement pourrait effectivement vous fournir certains inattendu nanosecondes lorsque vous essayez de mettre dans toute les millisecondes. Je pense que c'est la raison pour laquelle ils ont choisi d'arrondir la valeur à l'ensemble de millisecondes et jeter les petits chiffres.

7voto

alpha-mouse Points 2956

Sur les droits de la spéculation..

  1. TimeSpan.MaxValue.TotalMilliseconds est equat pour 922337203685477. Le numéro de 15 chiffres.
  2. double précision de 15 chiffres.
  3. TimeSpan.FromSeconds, TimeSpan.FromMinutes etc. tous passer par la conversion en millisecondes exprimé en double (puis à tiques puis de TimeSpan ce qui n'est pas intéressant)

Ainsi, lorsque vous créez TimeSpan qui sera proche de TimeSpan.MaxValue (ou MinValue) de la conversion sera précis de millisecondes seulement.
Donc la probable réponse à la question "pourquoi" est: d'avoir la même précision de tous les temps.
Autre chose à penser est de savoir si la poste aurait pu faire mieux si les conversions ont été effectuées par le biais de la conversion d'une part de la valeur pour les tiques exprimé en long.

4voto

Dan Tao Points 60518

Imaginez que vous êtes le développeur responsable de la conception de l' TimeSpan type. Vous avez toutes les fonctionnalités de base en place, tout semble fonctionner parfaitement. Puis un jour, des bêta-testeur arrive et vous montre ce code:

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);

Pourquoi est-ce que la sortie False? le testeur vous la demande. Même si vous comprenez pourquoi c'est arrivé (la perte de précision en additionnant x et y), vous avez de l'admettre, il ne sembler un peu étrange, d'un point de vue du client. Puis il jette de celui-ci à vous:

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

Que l'une des sorties True! Le testeur est naturellement sceptiques.

À ce stade, vous avez une décision à prendre. Soit vous pouvez vous permettre une opération arithmétique entre TimeSpan valeurs qui ont été construits à partir de double valeurs pour produire un résultat dont la précision dépasse la précision de l' double type lui-même-par exemple, 100000000000000.5 (16 chiffres significatifs) ou vous pouvez, vous le savez, de ne pas permettre cela.

À vous de décider, vous savez quoi, je vais juste faire en sorte que toute méthode qui utilise un double à la construction d'un TimeSpan seront arrondis au millième de seconde. De cette façon, il est explicitement documentées que la conversion à partir d'un double d'un TimeSpan est une perte de fonctionnement, de le dispenser de moi dans le cas où un client voit le comportement bizarre comme cette après la conversion de double de TimeSpan et l'espoir d'un résultat précis.

Je ne suis pas nécessairement en soutenant que c'est la "bonne" décision ici; à l'évidence, cette approche provoque une certaine confusion sur son propre. Je dis juste qu'une décision devait être faite d'une façon ou l'autre, et c'est ce qui était apparemment décidé.

1voto

Simon Mourier Points 49585

Je pense que l'explication est là: la structure TimeSpan ne gère pas correctement les valeurs proches des valeurs min et max

Et il semble que cela ne changera pas de sitôt :-)

0voto

SeeSharp Points 1195

FromSeconds utilise la méthode privée Interval

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

0x3e8 == 1000

Valeur multijoueur de la méthode d'intervalle sur cette constante puis transtypée en long (voir dernière ligne):

 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!!!
}
 

En conséquence, nous avons la précision avec 3 signes (x1000). Utilisez le réflecteur pour enquêter

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X