C #: уменьшение часов с использованием модуля математики - PullRequest
6 голосов
/ 21 ноября 2010

Попытка эмулировать опрокидывание 24-часовых часов вручную (с математикой против использования классов временного интервала). Инкрементную часть было легко понять, как переворачивать с 23:00 до 0:00 и обратно, но заставить его пойти другим путем оказывается действительно непонятным. Вот что у меня есть:

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

Проблема, которую я нахожу, заключается в том, что при движении назад, если модуль находится между числами, он не будет правильно уменьшаться. Пример: это 12:00, а вы вычитаете 61 минуту, мы знаем, что время будет 10:59, так как час должен откатиться на 1 час для перехода с 12:00 до 11:59, а затем снова на переход от 11:00 до 10:59. К сожалению, способ, которым я его вычисляю: newMin% 60 в этом случае захватывает только откат первого часа, но так как второй откат технически равен -1.0166 как остаток, и так как мод возвращает только целое число, его округление округляется. Я уверен, что мне здесь не хватает элементарной математики, но кто-нибудь может мне помочь?

РЕДАКТИРОВАТЬ: Я написал это несколькими способами, длинными и короткими. Некоторые ближе, чем другие, но я знаю, что это проще, чем кажется. Я знаю, что это похоже на то, «что он делал», но вы должны в основном увидеть, что я пытаюсь сделать. Увеличить часы и перенести их с 23:59 на 0:00 легко. Движение назад оказалось не таким легким.

ОК, вот время увеличения с переключением. Просто. Но попробуйте вернуться назад. Не работает.

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

Ответы [ 5 ]

1 голос
/ 21 ноября 2010

Я бы пошел на что-то немного проще

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

Пример использования:

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
1 голос
/ 21 ноября 2010

Вы можете сначала попытаться рассчитать как минутные, так и часовые приращения, а затем обрабатывать случаи, когда новые минуты пересекают часовую границу, что-то вроде этого:

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

Редактировать

Мне нравится ответ @Ben Voigts, но мне было интересно, будет ли разница в производительности. Я запустил консольное приложение ниже, чтобы рассчитать их время, и был немного удивлен результатами.

  • 40 мс для кода выше
  • 2876 мс для ответа Бена

Это было сделано в сборке релиза. Может ли кто-нибудь еще запустить это и подтвердить? Я делаю какие-либо ошибки в том, как я их измеряю?

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 голосов
/ 21 февраля 2012

зачем усложнять вещи

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)
    }
0 голосов
/ 21 ноября 2010

Попробуйте

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

        min -= hourIncrement * 60;

Существенной проблемой было то, что вы хотите, чтобы hourIncrement округлялось вниз, а целочисленное деление округлялось до нуля.Они одинаковы с положительными числами, но не с отрицательными ...

РЕДАКТИРОВАТЬ (избавляясь от бесполезной дополнительной переменной):

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

РЕДАКТИРОВАТЬ 2 (избегайте арифметики с плавающей точкой)

    min += incr;
    int hourIncrement = min / 60;
    min -= hourIncrement * 60;
    if (min < 0) { min += 60; --hourIncrement; }
0 голосов
/ 21 ноября 2010

Модульная математика определяется только для целых чисел.Если вы пытаетесь смешать модульную арифметику с действительными числами, у вас ничего не получится.Вам нужно найти другой математический подход.

...