views:

337

answers:

5

I'm in a very performance-sensitive portion of my code (C#/WPF), and I need to perform a modulus operation between two System.TimeSpan values in the quickest way possible.

This code will be running thousands of times per second, and I would very much prefer to avoid using a manual loop calculation - at all costs.

The idea of a modulus between two TimeSpans may seem a little weird, so allow me to explain -
Say we have
TimeSpan A = 1 Minute 30 Seconds
TimeSpan B = 20 Seconds

Here would be a list of common operations and their reasonable results:

A + B = (TimeSpan)1 Minute 50 Seconds

A - B = (TimeSpan)1 Minute 10 Seconds

A * B = No Reasonable Way to Compute
We should be able to multiply a TimeSpan by an integer. A * 5 = (TimeSpan) 7 Minutes 30 Seconds
Microsoft has not implemented multiplication between TimeSpans and integers.

A / B = (int)4 or (double)4.5
This operation is not implemented directly in the .NET framework, but it makes perfect sense.
There are 4.5 B's in A. (4.5 * 20 = 90)

A % B = (TimeSpan) 10 Seconds
Given reasonable TimeSpan division, TimeSpan modulus should be pretty straight-forward.
A / B really equals (int)4 remainder (TimeSpan)10 Seconds. The quotient and remainder are different data types, which may in fact be why Microsoft hasn't implemented this directly.

I need to find an efficient way to compute this without looping. Normally I wouldn't be opposed to a short loop, but these TimeSpans could differ greatly. The larger the exponential difference between the TimeSpans, the larger the quotient. The larger the quotient, the more iterations a "divide-loop" will have to execute. This is a dependency that I cannot allow in this part of my app.

Does SO have any ideas?

+4  A: 

If you can convert away from a time span to the number of seconds it represents, you can mod those values and then convert back.

Jonathan
+5  A: 

Would something like

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

give you the result you want? Would Ticks be the right unit to do the work? Maybe you'd need to convert the span into seconds or milliseconds or something. I don't know what your application for this is.

Michael Burr
+16  A: 

Multiplication is easy:

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

Likewise A/B:

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

And A%B:

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

Demonstration:

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

Output:

00:07:30
4.5
00:00:10
Jon Skeet
wouldn't this create a ton of objects awaiting garbage disposal? Wouldn't keeping track of the time using milliseconds or ticks as a long be better in the end?
ADB
TimeSpan is a struct and therefore isn't going to be burning up the GC.
sixlettervariables
+3  A: 

I wouldn't do this directly with the timespan object, but use the ticks ability.

Something like this.

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

You can condense, it into 1 step, but I did this to illustrate. It makes it nice and easy to do any mathematical operation that you desire.

Mitchel Sellers
+1  A: 

The best I can think of is to use the TotalSeconds Property and modulo it. However, they are Double, allow for fractional values and therefore, may not reach the exact values you are seeking for. You could always get the whole portions and modulo them but since you are worried about speed, I fear this may be too slow for an operation that must run hundreds of times a second.

Leahn Novash