C #: уменьшение часа с использованием модуля математики
Вопрос
Пытаясь эмулировать ролловер круглосуточной часы вручную (с математикой по сравнению с классами TimeSpan). Вырачающая часть была легко выясшена, как перевернуться с 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 как остаток, и поскольку мод возвращает только целое число, его округление. Я уверен, что я скучаю по математике, но мог ли кто-нибудь помочь мне?
Редактировать: Я написал это несколько способов долго и коротко. Некоторые ближе, чем другие, но я знаю, что это проще, чем кажется. Я знаю, что этот кажется вроде «WTF, который он сделал», но вы сможете увидеть в основном то, что я пытаюсь сделать. Увеличение часов и наличие его опрокидывания с 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);
}
Решение
Я бы пошел на что-то немного проще
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
Другие советы
Вы можете попробовать вычисление как минуту, так и часовые приращения сначала, а затем обрабатывающие случаи, когда новые минуты пересекают почасовую границу, что-то подобное:
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;
}
}
}
Модульная математика определяется только для целых чисел. Если вы пытаетесь смешать модульную арифметику с реальными числами, вам не удастся. Вам нужно выяснить другой математический подход.
Пытаться
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; }
Зачем усложнять вещи
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)
}