Domanda

Il tentativo di emulare il ribaltamento di un orologio di 24 ore a mano (con la matematica vs. utilizzando le classi TimeSpan). La parte incremento è stato facile capire come rotolare 23:00-00:00 e da, ma riuscite a farla andare nella direzione opposta si sta rivelando essere davvero confuso. Ecco quello che ho finora:

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

Il problema che im constatazione è quando si va a ritroso, se il il modulo è tra i numeri, non sarà diminuire in modo corretto. Esempio: è 12:00 e si sottrae 61 minuti, sappiamo che il tempo sarebbe 10:59 come l'ora dovrebbe rotolare indietro 1 ora per andare 12:00-11:59, poi di nuovo per andare da 11:00 a 10:59. Purtroppo il modo im calcolarlo: newMin% 60 in questo caso, afferra solo il primo ripristino ora, ma poiché il secondo ripristino è tecnicamente -1,0166 come resto, e poiché mod restituisce solo un numero intero, il suo arrotondamento. Sono sicuro che im manca qualche matematica di base qui, ma qualcuno potrebbe aiutarmi?

EDIT: Ho scritto questo un certo numero di modi lungo e corto. Alcuni sono più vicino di altri, ma so che questo è più semplice di quanto sembri. So che questo sembra un pò "WTF stava facendo", ma si dovrebbe essere in grado di vedere in fondo che cosa Im cercando di fare. Incremento un orologio e averlo rollover 23:59-00:00 è facile. Andando a ritroso ha dimostrato di essere non così facile.

OK, ecco l'incrementMinute con il rollover. Semplice. Ma cercare di andare a ritroso. Non funziona.

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);
        }
È stato utile?

Soluzione

mi piacerebbe andare per qualcosa di un po 'più semplice

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

Utilizzo di esempio:

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

Altri suggerimenti

Si potrebbe provare a calcolare sia incrementi di ore e dei minuti, poi la gestione dei casi in cui le nuove minuti attraversa un confine ora, qualcosa di simile:

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++;
}

Modifica

mi piace @ Ben Voigts risposta, ma si chiedeva se ci sarebbe alcuna differenza in termini di prestazioni. Ho eseguito l'applicazione console di seguito per tempo tutti e due, ed ero un po 'sorpreso dai risultati.

  • 40 ms per il codice di cui sopra
  • 2876 ms per la risposta di Ben

Ciò è stato fatto in una build di rilascio. chiunque altro può eseguire questo e confermare? Am I commettere errori nel tempo mio modo loro?

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

matematica modulari è definito solo per gli interi. Se si sta tentando di mescolare aritmetica modulare con i numeri reali non avrà successo. Hai bisogno di capire un diverso approccio matematico.

Prova

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

        min -= hourIncrement * 60;

Il problema essenziale è che si desidera hourIncrement a giù turno, ma giri divisione intera verso lo zero. Sono la stessa cosa con i numeri positivi, ma non per negativo ...

EDIT (sbarazzarsi di variabile in più inutile):

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

EDIT2 (evitare virgola mobile):

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

Perché a complicare le cose

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)
    }
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top