题
尝试手动模拟 24 小时时钟的翻转(数学与数学)使用时间跨度类)。递增部分很容易弄清楚如何从 23:00 滚动到 0: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,因为从 12:00 到 11:59 的时间应回滚 1 小时,然后从 11:00 到 10 点的时间应回滚 1 小时:59。不幸的是我计算它的方式:newMin % 60 在这种情况下,仅获取第一个小时的回滚,但由于第二个回滚在技术上是 -1.0166 作为余数,并且由于 mod 仅返回整数,因此四舍五入。我确信我在这里缺少一些基本的数学知识,但是有人可以帮助我吗?
编辑:我已经用多种方式或长或短地写了这篇文章。有些比其他更接近,但我知道这比看起来更简单。我知道这看起来有点“他在做什么”,但你应该能够基本上看到我想做什么。增加时钟并使其从 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 毫秒
- Ben 的回答需要 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
到回合下来,但整数除法轮趋向于零。他们与正数一样,但不是消极...
EDIT(摆脱无用额外的变量的):
min += incr;
int hourIncrement = (int)Math.Floor(min / 60.0);
min -= hourIncrement * 60;
EDIT2(避免浮点运算):
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)
}