C#:使用模数学递减时钟

发布于 2024-10-03 05:00:49 字数 1215 浏览 1 评论 0原文

尝试手动模拟 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 点 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);
        }

Trying to emulate the rollover of a 24 hour clock by hand (with math vs. using the timespan classes). The incrementing part was easy to figure out how to roll over from 23:00 to 0:00 and from, but getting it to go the other way is turning out to be really confusing. Here's what I have so far:

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

The problem that im finding is when going backwards, if the the modulus of is between numbers, it will not decrement correctly. Example: it is 12:00 and you subtract 61 minutes, we know the time would be 10:59 as the hour should roll back 1 hour for going from 12:00 to 11:59, then back again for going from 11:00 to 10:59. Unfortunately the way im calculating it: newMin % 60 in this case, only grabs the first hour rollback, but since the second rollback is technically -1.0166 as a remainder, and since mod only returns a whole number, its rounding off. Im sure im missing some basic math here, but could someone help me out?

EDIT: I've written this a number of ways long and short. Some are closer than others, but I know this is simpler than it seems. I know this one seems kinda "wtf was he doing", but you should be able to see basically what Im trying to do. Incrementing a clock and having it rollover from 23:59 to 0:00 is easy. Going backwards has proven to be not so easy.

OK, here's the incrementMinute with the rollover. Simple. But try to go backwards. Doesn't work.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

蘸点软妹酱 2024-10-10 05:00:49

我会选择更简单的

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

I'd go for something a bit simpler

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

Sample usage :

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
夏尔 2024-10-10 05:00:49

您可以尝试首先计算分钟和小时增量,然后处理新分钟跨越小时边界的情况,如下所示:

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

You might try calculating both minute and hour increments first, then handling cases where the new minutes crosses an hour boundary, something like this:

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

Edit

I like @Ben Voigts answer, but was wondering if there would be any difference in performance. I ran the console application below to time them both, and was a little surprised by the results.

  • 40 ms for the code above
  • 2876 ms for Ben's answer

This was done in a release build. Can anyone else run this and confirm? Am I making any mistakes in the way I time them?

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;
        }
    }
}
和我恋爱吧 2024-10-10 05:00:49

模数学仅针对整数定义。如果您尝试将模运算与实数混合,您将不会成功。您需要找出一种不同的数学方法。

Modular mathematics is only defined for the integers. If you are attempting to mix modular arithmetic with real numbers you will not succeed. You need to figure out a different mathematical approach.

还如梦归 2024-10-10 05:00:49

尝试

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

Try

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

        min -= hourIncrement * 60;

The essential problem was that you want hourIncrement to round down, but integer division rounds toward zero. They're the same with positive numbers, but not for negative...

EDIT (getting rid of useless extra variable):

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

EDIT2 (avoid floating-point arithmetic):

    min += incr;
    int hourIncrement = min / 60;
    min -= hourIncrement * 60;
    if (min < 0) { min += 60; --hourIncrement; }
無處可尋 2024-10-10 05:00:49

为什么要把事情复杂化

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

Why to complicate things

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)
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文