Question

Essayer d'imiter le roulement d'une horloge de 24 heures à la main (avec les mathématiques par rapport à l'utilisation des classes TimeSpan). La partie incrémenter était facile de comprendre comment rouler 23h00-0h00 et de, mais l'obtenir pour aller dans l'autre sens se avère être vraiment déroutant. Voici ce que j'ai à ce jour:

static void IncrementMinute(int min, int incr)
{
    int newMin = min + incr,
                hourIncrement = newMin / 60;

    //increment or decrement the hour
    if((double)newMin % 60 < 0 && (double)newMin % 60 > -1)
        hourIncrement = -1;

    Console.WriteLine("Hour increment is {0}: ", hourIncrement);
}

Le problème que la constatation im est en train de reculer, si le module d'entre nombres, il ne sera pas décrémenter correctement. Exemple: il est 12h00 et vous soustrayez 61 minutes, nous savons que le temps serait 10h59 que l'heure devrait revenir 1 heure pour aller 12h00-11h59, puis de nouveau pour aller de 11h00 à 10h59. Malheureusement, la façon im le calculer: newMin% 60 dans ce cas, saisit seulement la première rollback heure, mais depuis la deuxième rollback est techniquement -1,0166 comme reste, et puisque mod retourne un nombre entier, son arrondissement. Je suis sûr que im manque un peu de mathématiques de base, mais pourrait aider quelqu'un me sortir?

EDIT: Je l'ai écrit plusieurs façons long et court. Certains sont plus proches que d'autres, mais je sais que cela est plus simple qu'il n'y paraît. Je sais que ce ne semble un peu « wtf qu'il faisait », mais vous devriez être en mesure de voir essentiellement ce que Im essayant de faire. Incrémenter une horloge et ayant ce renversement 23h59-0h00 est facile. VAIS a en arrière avéré être pas si facile.

OK, voici le incrementMinute avec le roulement. Facile. Mais essayer de revenir en arrière. Ne fonctionne pas.

static void IncrementMinute(int min, int incr)

        {
            int newMin = min + incr,
                hourIncrement = newMin / 60;

            min = newMin % 60;

            Console.WriteLine("The new minute is {0} and the hour has incremented by {1}", min, hourIncrement);
        }
Était-ce utile?

La solution

Je vais pour quelque chose peu plus simple

public class Clock
{
    public const int HourPerDay = 24;
    public const int MinutesPerHour = 60;
    public const int MinutesPerDay = MinutesPerHour * HourPerDay;

    private int totalMinutes;

    public int Minute
    {
        get { return this.totalMinutes % MinutesPerHour; }
    }

    public int Hour
    {
        get { return this.totalMinutes / MinutesPerHour; }
    }

    public void AddMinutes(int minutes)
    {
        this.totalMinutes += minutes;
        this.totalMinutes %= MinutesPerDay;
        if (this.totalMinutes < 0)
            this.totalMinutes += MinutesPerDay;
    }

    public void AddHours(int hours)
    {
        this.AddMinutes(hours * MinutesPerHour);
    }

    public override string ToString()
    {
        return string.Format("{0:00}:{1:00}", this.Hour, this.Minute);
    }
}

Exemple d'utilisation:

new Clock().AddMinutes(-1);    // 23:59
new Clock().AddMinutes(-61);   // 22:59
new Clock().AddMinutes(-1441); // 23:59
new Clock().AddMinutes(1);     // 00:01
new Clock().AddMinutes(61);    // 01:01
new Clock().AddMinutes(1441);  // 00:01

Autres conseils

Vous pouvez essayer de calculer les deux tranches d'une minute et une heure d'abord, puis le traitement des cas où les nouvelles minutes traverse une frontière d'heure, quelque chose comme ceci:

int hourIncrement = incr / 60;
int minIncrement = incr % 60;

int newMin = min + minIncrement;

if (newMin < 0)
{
    newMin += 60;
    hourIncrement--;
}
else if (newMin > 60)
{
    newMin -= 60;
    hourIncrement++;
}

Modifier

Je comme réponse @Ben Voigts, mais je me demandais s'il y aurait une différence de performance. J'ai couru l'application de la console ci-dessous pour les deux temps, et fut un peu surpris par les résultats.

  • 40 ms pour le code ci-dessus
  • 2876 ms pour la réponse de Ben

Cela a été fait dans une version release. Quelqu'un peut-il exécuter d'autre cela et confirmer? Suis-je faire des erreurs dans le temps que je voie les?

using System;
using System.Diagnostics;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Stopwatch sw = new Stopwatch();

            int max = 100000000;

            sw.Start();
            for (int i = 0; i < max; i++)
                IncrementMinute1(0, -61);
            sw.Stop();

            Console.WriteLine("IncrementMinute1: {0} ms", sw.ElapsedMilliseconds);

            sw.Reset();

            sw.Start();
            for (int i = 0; i < max; i++)
                IncrementMinute2(0, -61);
            sw.Stop();

            Console.WriteLine("IncrementMinute2: {0} ms", sw.ElapsedMilliseconds);

            Console.ReadLine();
        }

        static void IncrementMinute1(int min, int incr)
        {
            int hourIncrement = incr / 60;
            int minIncrement = incr % 60;

            int newMin = min + minIncrement;

            if (newMin < 0)
            {
                newMin += 60;
                hourIncrement--;
            }
            else if (newMin > 60)
            {
                newMin -= 60;
                hourIncrement++;
            }
        }

        static void IncrementMinute2(int min, int incr)
        {
            min += incr;
            int hourIncrement = (int)Math.Floor(min / 60.0);
            min -= hourIncrement * 60;
        }
    }
}

mathématiques modulaires est uniquement définie pour les nombres entiers. Si vous essayez de mélanger arithmétique modulaire avec des nombres réels, vous ne réussirez pas. Vous devez déterminer une approche mathématique différente.

Essayez

        int newMin = min + incr,
            hourIncrement = (int)Math.Floor(newMin / 60.0);

        min -= hourIncrement * 60;

Le problème essentiel est que vous voulez hourIncrement vers le bas tour, mais tours de division entière vers zéro. Ils sont les mêmes avec des chiffres positifs, mais pas négatif ...

EDIT (se débarrasser de la variable supplémentaire inutile):

    min += incr;
    int hourIncrement = (int)Math.Floor(min / 60.0);
    min -= hourIncrement * 60;

EDIT2 (éviter arithmétique à virgule flottante):

    min += incr;
    int hourIncrement = min / 60;
    min -= hourIncrement * 60;
    if (min < 0) { min += 60; --hourIncrement; }

Pourquoi compliquer les choses

public System.Timers.Timer timer = new System.Timers.Timer(1000);
public DateTime d;

public void init()
{
timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);

d = new DateTime(2011, 11, 11, 23, 59, 50);
d=d.AddHours(1);
Console.Writeline(d);
d=d.AddHours(-2);
Console.Writeline(d);
timer.Enabled = true;
}
   void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        this.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)(() =>
        {
            MoveClockHands();
            d=d.AddSeconds(1);
            Console.WriteLine(d);

        }));
    }

    void MoveClockHands()  //12 hours clock
    (
       s=d.Second * 6;
       m=d.Minute * 6;
       h=0.5 * ((d.Hour % 12) * 60 + d.Minute)
    }
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top