C#:モジュラス計算を使用してクロックをデクリメントする
質問
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 分を引くと、12:00 から 11:59 までは 1 時間戻り、11:00 から 10 まではまた戻るので、時刻は 10:59 になることがわかります。 :59。残念ながら、私がそれを計算する方法は次のとおりです。この場合、 newMin % 60 は最初の 1 時間のロールバックのみを取得しますが、2 番目のロールバックは技術的には剰余として -1.0166 であるため、また mod は整数のみを返すため、四捨五入されます。ここで基本的な数学が欠けていると思いますが、誰かが私を助けてくれませんか?
編集:これまで長短いろいろ書いてきました。他のものよりも近いものもありますが、これが思っているよりも簡単であることはわかっています。これは「なんと彼はやっていたのか」と思われることはわかっていますが、基本的に私が何をしようとしているのかはわかるはずです。時計を増やして 23:59 から 0:00 にロールオーバーするのは簡単です。過去に戻るのはそれほど簡単ではないことがわかっています。
OK、これがロールオーバーを伴うincrementMinuteです。単純。しかし、後戻りしてみてください。機能しません。
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
をしたいが、ゼロに向けて整数の除算の丸めということでした。彼らは正の数と同じだが、ない負のために...
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)
}