如何在不循环的情况下使用System.TimeSpan值进行模数运算?

11

我正在处理非常注重性能的代码部分(C#/WPF),我需要以最快的方式执行两个System.TimeSpan值之间的模运算。

这段代码将每秒运行数千次,我非常希望尽可能地避免使用手动循环计算 - 不惜一切代价。

两个TimeSpan之间进行取模的想法可能有点奇怪,所以请允许我解释一下 -
假设我们有
TimeSpan A = 1分钟30秒
TimeSpan B = 20秒

这里是一些常见操作及其合理结果的列表:

A + B = (TimeSpan)1分钟50秒

A - B = (TimeSpan)1分钟10秒

A * B = 没有合理的计算方法
我们应该能够通过整数乘以TimeSpan。A * 5 = (TimeSpan) 7 分钟30秒
Microsoft未实现TimeSpan和整数之间的乘法。

A / B = (int)4或(double)4.5
这个操作没有直接在.NET框架中实现,但非常合理。
A中有4.5个B。(4.5 * 20 = 90)

A % B = (TimeSpan) 10 秒
由于有合理的TimeSpan除法,TimeSpan取模应该非常简单。
A / B 真的等于(int)4 余数(TimeSpan)10秒。商和余数是不同的数据类型,这可能是微软没有直接实现它的原因。

我需要找到一种不用循环计算的高效方法。通常我不会反对短循环,但这些TimeSpans可能差别很大。TimeSpans之间的指数差异越大,商就越大。商越大,“除-循环”将要执行的迭代次数就越多。这是我不能允许的依赖关系。

Stack Overflow有什么想法吗?


答案非常显而易见。我感觉自己像个傻瓜,哈哈。谢谢 Stack Overflow! - Giffyguy
1
一旦你有了答案,一切看起来都很简单。 - Steven Sudit
5个回答

27

乘法很简单:

TimeSpan a5 = TimeSpan.FromTicks(A.Ticks * 5);

同样适用于 A/B:

double aOverB = (double)A.Ticks / B.Ticks;

以及 A%B:

TimeSpan aModB = TimeSpan.FromTicks(A.Ticks % B.Ticks);

演示:

using System;

class Test
{
    static void Main()
    {
        TimeSpan a = TimeSpan.FromSeconds(90);
        TimeSpan b = TimeSpan.FromSeconds(20);

        TimeSpan a5 = TimeSpan.FromTicks(a.Ticks * 5);
        double aOverB = (double)a.Ticks / b.Ticks;
        TimeSpan aModB = TimeSpan.FromTicks(a.Ticks % b.Ticks);

        Console.WriteLine(a5);
        Console.WriteLine(aOverB);
        Console.WriteLine(aModB);
    }
}

输出:

00:07:30
4.5
00:00:10

这样做不会创建大量等待垃圾处理的对象吗?最终使用毫秒或滴答作为长整型来跟踪时间不是更好吗? - ADB
6
TimeSpan 是一个结构体,因此不会对垃圾收集器造成太大的负担。 - user7116

6

Would something like

new TimeSpan( A.Ticks % B.Ticks))

您希望得到想要的结果吗?Ticks是正确的计量单位吗?也许您需要将时间间隔转换为秒或毫秒等。我不知道您使用这个的目的。


4

如果你能将时间跨度转换为它所代表的秒数,那么你可以对这些值进行取模,然后再转换回去。


4
我不会直接使用TimeSpan对象,而是使用ticks的能力。
就像这样。
TimeSpan oSpan = new TimeSpan(0, 1, 20, 0, 0);
TimeSpan oShort = new TimeSpan(0, 0, 20, 0, 0);
long modRemainder = oSpan.Ticks % oShort.Ticks;
TimeSpan oRemainderSpan = new TimeSpan(modRemainder);

你可以将它压缩成一个步骤,但我这样做是为了说明。这使得你可以轻松进行任何你想要的数学运算。

1
我所能想到的最好方法是使用TotalSeconds属性并对其取模。但是,它们是双精度浮点型,允许小数值,因此可能无法达到您寻求的精确值。您可以始终获取整个部分并对其取模,但由于您担心速度问题,我担心这可能对必须每秒运行数百次的操作来说太慢了。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接