需要优化计数正负值

时间:2011-10-10 13:16:04

标签: c# .net optimization .net-4.0

我需要优化计算pos / neg值的代码并按时间删除不合格的值。

我有附加时间戳的值队列。
我需要丢弃1ms的值并计算负值和正值。这里是伪代码

list<val> l;
v = q.dequeue();
deleteold(l, v.time);
l.add(v);
negcount = l.count(i => i.value < 0);
poscount = l.count(i => i.value >= 0);
if(negcount == 10) return -1;
if(poscount == 10) return  1;

我需要在c#中以最大速度运行此代码。无需坚持清单。事实上,欢迎以neg和pos值分隔的数组。

编辑:可能不安全的数组将是最好的。任何提示?

编辑:感谢您的抬头.. 我快速测试了阵列版本与列表(我已经拥有)并且列表更快:35 vs 16 ms,1 mil迭代... < / p>

这是公平的代码:

class Program
{
    static int LEN = 10;
    static int LEN1 = 9;

    static void Main(string[] args)
    {
        Var[] data = GenerateData();

        Stopwatch sw = new Stopwatch();

        for (int i = 0; i < 30; i++)
        {
            sw.Reset();
            ArraysMethod(data, sw);

            Console.Write("Array: {0:0.0000}ms     ", sw.ElapsedTicks / 10000.0);

            sw.Reset();
            ListMethod(data, sw);

            Console.WriteLine("List: {0:0.0000}ms", sw.ElapsedTicks / 10000.0);
        }

        Console.ReadLine();
    }

    private static void ArraysMethod(Var[] data, Stopwatch sw)
    {
        int signal = 0;
        int ni = 0, pi = 0;
        Var[] n = new Var[LEN];
        Var[] p = new Var[LEN];
        for (int i = 0; i < LEN; i++)
        {
            n[i] = new Var();
            p[i] = new Var();
        }

        sw.Start();
        for (int i = 0; i < DATALEN; i++)
        {
            Var v = data[i];

            if (v.val < 0)
            {
                int x = 0;
                ni = 0;
                // time is not sequential
                for (int j = 0; j < LEN; j++)
                {
                    long diff = v.time - n[j].time;
                    if (diff < 0)
                        diff = 0;

                    // too old
                    if (diff > 10000)
                        x = j;
                    else
                        ni++;

                }

                n[x] = v;

                if (ni >= LEN1)
                    signal = -1;

            }
            else
            {
                int x = 0;
                pi = 0;
                // time is not sequential
                for (int j = 0; j < LEN; j++)
                {
                    long diff = v.time - p[j].time;
                    if (diff < 0)
                        diff = 0;

                    // too old
                    if (diff > 10000)
                        x = j;
                    else
                        pi++;

                }

                p[x] = v;

                if (pi >= LEN1)
                    signal = 1;
            }
        }
        sw.Stop();
    }

    private static void ListMethod(Var[] data, Stopwatch sw)
    {
        int signal = 0;
        List<Var> d = new List<Var>();

        sw.Start();
        for (int i = 0; i < DATALEN; i++)
        {
            Var v = data[i];


            d.Add(new Var() { time = v.time, val = v.val < 0 ? -1 : 1 });

            // delete expired
            for (int j = 0; j < d.Count; j++)
            {
                if (v.time - d[j].time < 10000)
                    d.RemoveAt(j--);
                else
                    break;
            }

            int cnt = 0;
            int k = d.Count;
            for (int j = 0; j < k; j++)
            {
                cnt += d[j].val;
            }

            if ((cnt >= 0 ? cnt : -cnt) >= LEN)
                signal = 9;
        }
        sw.Stop();
    }

    static int DATALEN = 1000000;
    private static Var[] GenerateData()
    {
        Random r = new Random(DateTime.Now.Millisecond);

        Var[] data = new Var[DATALEN];

        Var prev = new Var() { val = 0, time = DateTime.Now.TimeOfDay.Ticks};
        for (int i = 0; i < DATALEN; i++)
        {
            int x = r.Next(20);
            data[i] = new Var() { val = x - 10, time = prev.time + x * 1000 };
        }

        return data;
    }

    class Var
    {
        public int val;
        public long time;
    }

}

2 个答案:

答案 0 :(得分:3)

要获得negcount和poscount,您将遍历整个列表两次。 相反,遍历它一次(计算negcount),然后poscount = l.Count - negcount。

答案 1 :(得分:1)

一些想法:

  1. 仅在max(negcount,poscount)变为10之前计数,然后退出(不需要计算其余部分)。仅当10是最大计数时才有效。
  2. 计算一次性消极和正面项目。
  3. 仅计算negcount并从count-negcount推断poscount,这比计算它们更容易。
  4. 它们中的任何一个是否比现在更快,哪个更快,取决于数据通常的样子。是长吗?短?

    更多关于3:
    您可以使用欺骗来避免分支。您不必测试该项目是否为负数,您可以将其否定性添加到计数器中。假设该项为x并且它是int,则x >> 31对于正x为0,对于负x为-1。因此counter -= x >> 31会给negcount

    编辑:不安全的数组可以更快,但不应该在这种情况下,因为循环的形式是

    for (int i = 0; i < array.Length; i++)
        do something with array[i];
    

    由JIT编译器优化。