2010-11-21 12 views
6

Intentando emular la renovación de un reloj de 24 horas a mano (con matemática vs. usando las clases de tiempo). La parte de incremento fue fácil de entender cómo pasar de las 23:00 a las 0:00 y desde allí, pero lograr que vaya para el otro lado es realmente confuso. Esto es lo que tengo hasta ahora:C#: decrementando un reloj usando el módulo matemático

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

El problema que im hallazgo es cuando se va hacia atrás, si el módulo de es entre los números, no va a disminuir correctamente. Ejemplo: son las 12:00 y restas 61 minutos, sabemos que el tiempo sería 10:59 ya que la hora debería retroceder 1 hora para ir de 12:00 a 11:59, luego de vuelta para las 11:00 a 10:59. Lamentablemente, la forma de calcularlo: newMin% 60 en este caso, solo capta la primera hora de retroceso, pero dado que la segunda reversión es técnicamente -1.0166 como un resto, y dado que mod solo devuelve un número entero, se redondea. Estoy seguro de que me faltan algunas matemáticas básicas aquí, pero ¿podría alguien ayudarme?

EDITAR: He escrito esto de varias maneras. Algunos están más cerca que otros, pero sé que esto es más simple de lo que parece. Sé que este parece un poco "¿Qué estaba haciendo él?", Pero deberían poder ver básicamente lo que trato de hacer. Incrementar un reloj y hacer que se mueva de 23:59 a 0:00 es fácil. Retroceder ha demostrado no ser tan fácil.

OK, aquí está el incrementoMinute con la reinversión. Sencillo. Pero trata de ir hacia atrás. No funciona

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

¿Es posible añadir un poco más detalles de esto, en particular, un ejemplo de uso y estado esperado de la variable global? – steinar

+0

¿Qué valores tienen 'min' y' incr'? – ChrisF

+0

Creo que sí di esos ejemplos. Básicamente, ¿cómo codigo el decremento para tener 12:00 - 0:61 = 10:59 y hacer que funcione para incrementos también? – Sinaesthetic

Respuesta

1

me gustaría ir por algo un poco más 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); 
    } 
} 

Uso de la muestra:

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

En su función AddMinutes: s/if/while /, en caso de que el usuario agregue más de un día de minutos negativos. – jtdubs

+0

@jtdubs, 'this.totalMinutes% = MinutesPerDay;' se encarga de eso;) – Diadistis

+0

@Sinaesthetic, si va a utilizar esta clase, tenga en cuenta que no es segura para subprocesos. – Diadistis

0

Las matemáticas modulares solo se definen para los enteros. Si está intentando mezclar aritmética modular con números reales, no tendrá éxito. Necesitas descubrir un enfoque matemático diferente.

+0

el número real de conversión fue solo para ingresar a la estructura de control. Estaba intentando asegurarme de que restaría al menos 1 hora, pero descubrí que causaría problemas con la próxima disminución si fuera menos de 1 hora completa. confuso ... – Sinaesthetic

+0

sí, pero conceptualmente quieres ese resto. No va a suceder usando aritmética modular a menos que se separen las horas y los minutos antes de aplicar el módulo. – joejoeson

+0

las horas y los minutos se separan antes de aplicar el módulo. – Sinaesthetic

1

Usted puede tratar de calcular los dos incrementos de un minuto y la hora en primer lugar, a continuación, el manejo de casos en los que las nuevas minutos cruza una frontera hora, algo como esto:

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

Editar

me gusta @Ben Voigts respuesta, pero me preguntaba si habría alguna diferencia en el rendimiento. Ejecuté la aplicación de la consola a continuación para medir el tiempo de ambos, y me sorprendieron un poco los resultados.

  • 40 ms para el código anterior
  • 2876 ms para la respuesta de Ben

Esto se hizo en una versión de lanzamiento. ¿Alguien más puede ejecutar esto y confirmar? ¿Estoy cometiendo algún error en la forma en que los miro?

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

a primera vista, esto no funcionaría si se retrasara más de una hora. Esta es una especie de donde estaba en Hace aproximadamente una hora :( – Sinaesthetic

+0

@Sinaesthetic, tal vez estoy mal entendido, pero si comienzo con '== min y' 0' incr = -121', obtengo 'newMin == 59 'y' hourIncrement == -3' ¿es incorrecto que –

+0

@adrift:.?.! a mi me parece que debería funcionar, pero es más complicado de lo necesario –

0

Trate

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

     min -= hourIncrement * 60; 

El problema esencial es que desea hourIncrement para redondear hacia abajo, pero rondas división entera hacia cero. Son lo mismo con números positivos, pero no para negativos ...

EDITAR (deshacerse de inútil variables extra):

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

Edit2 (evitar la aritmética de punto flotante):

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

ok Math.Floor es lo que estaba buscando. No resuelve el retroceso minuto, pero obtuvo la parte con la que estaba luchando más. PIENSO que puedo obtenerlo de aquí gracias. – Sinaesthetic

+0

proporcioné código para hacerse cargo de la reversión minutos, pero metí por el hecho de que no estuviera realmente poniendo la nueva minutos en 'newMin'. Ver http: // ideone.com/i3Yom –

0

Por qué complicar las cosas

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