【问题标题】:C#: decrementing a clock using modulus mathC#:使用模数数学递减时钟
【发布时间】:2010-11-21 00:27:43
【问题描述】:

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

【问题讨论】:

  • 您能否为此添加更多细节,特别是全局变量的用法示例和预期状态?
  • minincr 有什么值?
  • 我相信我确实给出了这些例子。基本上,我如何将减量编码为 12:00 - 0:61 = 10:59 并使其也适用于增量。
  • 第三行 incr 后面的逗号是什么意思?
  • 简单的加减法怎么样?为我的时钟工作。

标签: c# math clock modulo


【解决方案1】:

我会选择更简单的东西

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

【讨论】:

  • 在您的 AddMinutes 函数中:s/if/while/,以防用户添加超过一天的负分钟数。
  • @jtdubs,this.totalMinutes %= MinutesPerDay; 负责处理 ;)
  • @Sinaesthetic,如果你要使用这个类,请记住它不是线程安全的。
【解决方案2】:

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

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

【讨论】:

  • 乍一看,如果你倒退一个多小时,这将不起作用。这是我大约一个小时前所处的地方:(
  • @Sinaesthetic,也许我理解错了,但如果我以min == 0incr = -121 开头,我会得到newMin == 59hourIncrement == -3。这不正确吗?
  • @adrift:在我看来它应该可以工作,但它比必要的复杂。
  • 对于最大值 = 1000000:IncrementMinute1:1345 毫秒,IncrementMinute2:1767 毫秒
  • @Didistis,那是发布版本吗?
【解决方案3】:

模数数学只为整数定义。如果您试图将模运算与实数混合使用,您将不会成功。您需要找出不同的数学方法。

【讨论】:

  • 实数铸造只是为了进入控制结构。我试图确保它会减去至少 1 小时,但我发现如果小于 1 个完整小时,它会导致下一次减量出现问题。令人困惑...
  • 是的,但从概念上讲,您想要剩余的部分。除非在应用模数之前将小时和分钟分开,否则使用模算术不会发生这种情况。
  • 在应用模数之前将小时和分钟分开。
【解决方案4】:

试试

        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;

EDIT2(避免浮点运算):

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

【讨论】:

  • ok Math.Floor 就是我想要的。不能解决一分钟的回滚,但它得到了我最挣扎的部分。我想我可以从这里得到它,谢谢。
  • 我提供了处理分钟回滚的代码,但因为您实际上并没有将新分钟放入 newMin 中而感到困惑。见ideone.com/i3Yom
【解决方案5】:

为什么要把事情复杂化

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-28
    • 2016-04-05
    • 2017-04-09
    • 1970-01-01
    • 2013-03-09
    相关资源
    最近更新 更多