2010-11-21 6 views
6

Versuchen, den Rollover einer 24-Stunden-Uhr von Hand zu emulieren (mit Mathe im Vergleich zu den Zeitspannen Klassen). Der inkrementierende Teil war leicht herauszufinden, wie man von 23:00 Uhr auf 0:00 Uhr und wieder zurück kommt, aber es in die andere Richtung zu bringen, erweist sich als wirklich verwirrend. Hier ist, was ich bisher:C#: Dekrementieren einer Uhr mit Modulo-Mathematik

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

Das Problem, das im Ergebnis ist, wenn nach hinten los, wenn das das E-Modul zwischen den Zahlen ist, wird es nicht richtig verringern. Beispiel: Es ist 12:00 und Sie subtrahieren 61 Minuten, wir wissen, dass die Zeit 10:59 Uhr ist, da die Stunde 1 Stunde zurückgehen sollte, um von 12:00 Uhr auf 11:59 Uhr zu gehen, und dann wieder zurück, um von 11:00 Uhr zu gehen bis 10:59. Leider ist die Art und Weise, wie es berechnet wird: newMin% 60 in diesem Fall, nimmt nur die erste Stunde Rollback, aber da der zweite Rollback ist technisch -1.0166 als Rest, und da Mod nur eine ganze Zahl zurückgibt, seine Abrundung. Ich bin mir sicher, dass ich hier ein paar Grundkenntnisse vermisse, aber könnte mir jemand helfen?

EDIT: Ich habe dies eine Reihe von Möglichkeiten lang und kurz geschrieben. Einige sind näher als andere, aber ich weiß, das ist einfacher als es scheint. Ich weiß, dass dieser hier irgendwie "wtf was er macht" scheint, aber du solltest im Grunde sehen können was ich versuche zu tun. Das Inkrementieren einer Uhr und das Rollover von 23:59 Uhr auf 0:00 Uhr ist einfach. Rückwärts gehen hat sich als nicht so einfach erwiesen.

OK, hier ist die incrementMinute mit dem Rollover. Einfach. Aber versuche rückwärts zu gehen. Funktioniert nicht.

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

erschweren Könnten Sie ein wenig mehr Details zu diesem Add, ein Anwendungsbeispiel und erwarteten Zustand der globalen Variablen im Besonderen? – steinar

+0

Welche Werte haben 'min' und' incr'? – ChrisF

+0

Ich glaube, ich habe diese Beispiele gegeben. Im Grunde, wie kann ich das Dekrement programmieren, um 12:00 - 0:61 = 10:59 zu haben und es auch für Inkremente arbeiten zu lassen. – Sinaesthetic

Antwort

1

ich für etwas ein bisschen einfacher

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); 
    } 
} 
gehen würde

Beispielverwendung:

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 
+0

In Ihrer AddMinutes-Funktion: s/if/while /, falls der Benutzer mehr als einen Tag negative Minuten hinzufügt. – jtdubs

+0

@jtdubs, 'this.totalMinutes% = MinutesPerDay;' kümmert sich darum;) – Diadistis

+0

@Sinästhetisch, wenn du diese Klasse verwenden willst, bedenke, dass sie nicht threadsicher ist. – Diadistis

0

Modulare Mathematik ist nur für Ganzzahlen definiert. Wenn Sie versuchen, modulare Arithmetik mit reellen Zahlen zu mischen, werden Sie nicht erfolgreich sein. Sie müssen einen anderen mathematischen Ansatz finden.

+0

die echte Nummer Casting war nur die Kontrollstruktur eingeben. Ich habe versucht, sicherzustellen, dass es mindestens 1 Stunde subtrahieren würde, aber ich fand heraus, dass es Probleme mit dem nächsten Dekrement verursachen würde, wenn es weniger als 1 volle Stunde war. verwirrend ... – Sinaesthetic

+0

ja, aber konzeptionell wollen Sie diesen Rest. Es wird nicht passieren, modulare Arithmetik zu verwenden, es sei denn, Sie trennen die Stunden und Minuten vor der Anwendung des Moduls. – joejoeson

+0

Die Stunden und Minuten werden vor dem Anlegen des Moduls getrennt. – Sinaesthetic

1

Sie könnten beide Minuten- und Stunden Schritte zunächst versuchen zu berechnen, dann die Bearbeitung von Fällen, wo die neuen Minuten eine Stunde-Grenze überschreiten, so etwas wie diese:

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

bearbeiten

Ich mag @ Ben Voigts Antwort, aber fragte sich, ob es einen Unterschied in der Leistung geben würde. Ich habe die Konsolenanwendung unten ausgeführt, um beide zu synchronisieren, und war ein wenig überrascht von den Ergebnissen.

  • 40 ms für den Code oben
  • 2876 ms für Bens Antwort

Dies wurde in einem Release-Build getan. Kann jemand anderes das ausführen und bestätigen? Mache ich irgendwelche Fehler in der Art, wie ich sie zeitlich passe?

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

auf den ersten Blick würde dies nicht funktionieren, wenn Sie mehr als eine Stunde rückwärts gingen. Dies ist eine Art von wo ich vor etwa einer Stunde war :( – Sinaesthetic

+0

@ Sinästhetic, vielleicht bin ich ein Missverständnis, aber wenn ich mit "min == 0" und "incr = -121" beginne, bekomme ich 'newMin == 59 ', und' hourIncrement == -3 '. Ist das falsch? –

+0

@adrift: Es sieht so aus, als ob es funktionieren sollte, aber es ist komplizierter als nötig. –

0

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

     min -= hourIncrement * 60; 

Das wesentliche Problem Versuchen war, dass man hourIncrement nach unten abrunden wollen, aber Integer-Division Runden gegen Null. Sie sind die gleichen mit positiven Zahlen, aber nicht für negative ...

EDIT (immer nutzloser zusätzliche Variable los):

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

EDIT2 (Vermeidung von arithmetischen Gleitkommaoperationen):

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

ok Math.Floor ist, was ich gesucht habe. Löst nicht den winzigen Rollback, aber es hat den Teil, den ich am meisten gekämpft habe. Ich denke, ich kann es von hier bekommen, danke. – Sinaesthetic

+0

Ich habe einen Code zur Verfügung gestellt, der sich um den winzigen Rollback kümmert, wurde aber dadurch durcheinander gebracht, dass Sie die neue Minute nicht wirklich in 'newMin' geschrieben haben. Siehe http: // ideone.com/i3Yom –

0

Warum Dinge

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