窃下以为不可能有比循环累加更快的了,既然是相加,不管它的存储是否连续,在内存里什么形式,都要取出来放到CPU的寄存器里去,不可能直接去把内存上存的01给加了。这样的话,对于一个整数数组,可以随机寻址,从第100加到第200寻址是很快的。应该不会有更快的了。

解决方案 »

  1.   

    按段相加是不是这个意思:先两个两个相加,得到50个和,在两个两个相加,得到25个和,如此继续下去,最后得到结果?
    如果你的计算机上有两颗CPU或者有超线程的话,这样做是有意义的,因为这样可以同时做两个加法,可是如果只是普通的CPU的话,这样做只有浪费时间。
      

  2.   

    不是这个意思,我的意思是把地址从100到200内存放的数值全部相加
    可以限制为都是byte型的例如
    地址               数值
    17888423100        66
    17888423101        34
    17888423102        21
    17888423103        78
    .........................
    17888423199        12把这个地址段内的全部相加求和
      

  3.   

    这是一篇文章,应该可以有点点帮助数据并行的研究   数据并行编程风格的一种定义(用于HPF标准[8])是由一种并行环境所代表的一种风格:单线索控制 
    一个全局的名字空间 
    松散地同步执行 
    通过这个我们说明一个单程序,其对数组定义操作,数组元素由编译器分配到各个处理器。实现可以允许处理器同步地操作,但许多程序结构将迫使同步-例如所有数组元素求和的计算。一个数据并行编译器(或环境)将提供某些基本的功能,以使大范围的算法有效地执行。一种数据并行语言将提供大多数--如果不是全部的--下列功能:全数组元素的操作 例如 a = b + 2*c, 其中a,b和c是数组。部分数组 指出一个数组的子集的能力:例如一行或一列。条件操作 根据数组元素或逻辑值的判断条件,对数组元素某个集合的操作能力。这允许一些操作,象在数组内对非零元素取反。归并 例如把一个数组中的全部元素相加求和的操作。移位 沿着一个数组的给定的维移动元素。这对模板操作是很重要的,这应用在图象处理中,例如求解微分方程。一般的通讯 例如从一个向量发送数据到一个三维数组的指定元素。并行前缀/后缀操作 例如一个正在运行的全部操作。对数据分配的控制 控制数据怎样在处理器间分配,控制对象的对准以减小通讯。注意这些是高级操作,能被有效地实现。用编译器并行化在某个数组元素上定义操作的等量循环是更难的。随着数据并行语言的研究,上面所列的越来越多的特点成为可得到的。最早的数据并行语言大约在1973年,关于ILLIAC IV[4]机器的。例如,IVTRAN[9]是以FORTRAN为基础,有一个并行DO结构(DO FOR ALL),其和IF同时使用表示并行中的条件操作。它也可以表示对给定的维进行计算,以暗示编译器数据怎样分配才能有最小的通讯。在同一年,一台数据并行ALFOL 60出现,是基于Glypnir[10]语言,它也有类数组表达式和一种并行IF语句。但是,并行对象被称为Super Words(swords),为匹配机器尺寸(处理器数)其被限制。后来,在1979年,基于Pascal的Actus[11],为定义一个更完全的操作集加入环和去尾移动(rotate,shift)以及归并操作。最近,一些数据并行语言已出现,他们是一些语言的很好扩展。例如,并行Pascal[12](NASA MPP,1983),增强的Fortran-Plus[13](AMT DAP,1990)和Connection Machine C*[14](Thinking Machines.1990)。虽然在九十年代初,出现一些语言,但是他们有太多的方言,并且也有依赖机器的一些特点。这意味着用户被局限于某个生产商,而且未来的用户不愿意学习一个特别的语言。在我们努力介绍一些标准时,HPF讨论组成立了,其肩负着定义一个数据并行Fortran标准的任务。 
    --------------------------------------------------------------------------------
    Copyright: NPACT  
      

  4.   

    是不是可以用数据库技术?先把要计算的大数组放入Access中,用数据库的Sum函数求和。
      

  5.   

    不管数据是什么类型的,也不管数据存放在内存里还是在cache里,加法总是要做100次的,所以复杂度都是100。
    cpu里的确有内存加内存的指令,但那不是在内存里面做加法,也是要把内存里的数据读到寄存器里面再做加法,最后再写到内存里面。
    如果你能力强的话,可以用汇编这样做:把数据成批拷贝到cache里面,那样比较快,然后从cache里面读数据到寄存器做加法,虽然复杂度没有减少,但是可以减少传输数据的时间,但是永远没有办法减少做加法的时间,除非使用并行计算。
      

  6.   

    同意raulredondo() 的看法。
    如果你是搞统计软件,那你自己也应该知道此类运算是极度耗资源的,数组一上了内存再处理,如果已经做到了这步,那还能改进的余地极小,VS2004中的VC有针对CPU的优化。。
      

  7.   

    在我的程序中,如果没有改变算法,识别一个1024*768幅面的RGB图片需要1.8秒,其中有频繁加法运算,如果舍弃加法这些加法运算,相同的运算可以提高到0.007秒,而我的系统中每秒至少30幅的图片产生,你们说是不是要改变一下这些算法?如果我不进行这些加法运算,则识别无法达到一定程度上的模糊识别,所以我不能舍去这个运算
      

  8.   

    不可以少加几次
    你看如下的算法,pMT是个指针for(m=0;m<lTempHeight;m++)
    {
    for(n=0;n<nMWidth;n++)
    {
    dSigmaT+=(double)pMT[0];
    dSigmaT+=(double)pMT[1];
    dSigmaT+=(double)pMT[2];
    pMT += 3;
    }
    }
      

  9.   

    是不是因为double转来转去,再做加法的比较慢?
    你处理每个图片的算法到底是怎么样的?
    其实你图片都有1024*768,如果里面的算法复杂度再大一些的话,算得慢也是很正常的。
      

  10.   

    可以开很多线程啊比如要加2000-3000之间的数
    可以每100数为一组创建一个线程。
    这样充分利用cpu。再有就是直接用汇编写代码,速度可以进一步优化。
      

  11.   

    首先,把Double类型改为Long类型或decimal类型,因为double类型是浮点运算,很慢,
    如果1024*768个int32类型相加,long(int64)类型就足够了。
    第二,镶套循环可以改为单循环,如
    for (i=m*n-1; i>=0; i--)
    {
      //加法代码
    }
    可以快很多,
    第三,循环变量直接使用指针,可以快一点
    for (p=Start; p<End; p+=3) {//代码} 可以再快一点,
    如果还达不到要求,那只有使用汇编语言写了,可以省去结果变量重复读出寄存器的问题,
    不过,我个人认为,还是要从算法复杂度上解决问题,因为计算机的运算速度是有限的,
    不可能做出超出极限的事情,多线程就不用考虑了,同一个CPU,不可能会更快了,不过
    可以提高线程的优先级.
      

  12.   

    你的算法至少可以优化为:
    int c = lTempHeight * nMWidth;for (int i = 0; i < c; i++)
    {
        dSigmaT+=(double)*pMT;
        pMT++;
    }如果你的代码里面确实就只有这几句话,没有更多的跟长宽相关的东西。
    for(n=0...)本身包含了一次和循环本身没有关系的赋值,也就是说如果你for(m...)这里循环1000次,那就会多一千个赋值。此外,不知道pMT[2]这样子的语句是否会比*pMT慢一点?因为也许pMT[2]的汇编是
    mov ah, [esi+ebx]
    而*pMT的汇编是
    mov ah, [esi]
    此外,如果你这个dSigmaT本身在循环内部仅仅是相加,而没有别的什么浮点运算的话,那么我建议你进一步改成:
    int c = lTempHeight * nMWidth;
    int iTmp = 0;for (int i = 0; i < c; i++)
    {
        iTmp += *pMT;
        pMT++;
    }dSigmaT = (double) iTmp;
    要知道浮点的加可是比整数的加慢的多!此外,你这是用C#写呢还是VC.NET写?如果你对速度有要求,建议你用VC.NET写这一部分的代码,然后对结果用Managed Code输出,这样C#可以利用,而又提高了运行速度。
      

  13.   

    〉  你的算法至少可以优化为:
    〉  int c = lTempHeight * nMWidth;
    〉  
    〉  for (int i = 0; i < c; i++)
    〉  {
    〉      dSigmaT+=(double)*pMT;
    〉      pMT++;
    〉  }
    这是不可以的,之所以需要圈套循环,原因是因为有些地方需要跳转一个段,上头只是一个小的循环,大循环中还需要如下的算法for(m=0;m<lTempHeight;m++)
    {
    for(n=0;n<nMWidth;n++)
    {
    dSigmaT+=(double)pMT[0];
    dSigmaT+=(double)pMT[1];
    dSigmaT+=(double)pMT[2];
    pMT += 3;
    }
             pMT += (nWidth + nOffset) * 3;
    }其中 nWidth 和 nOffset 是其它的两个long型变量>   此外,不知道pMT[2]这样子的语句是否会比*pMT慢一点?因为也许pMT[2]的汇编是
    >   mov ah, [esi+ebx]
    >   而*pMT的汇编是
    >   mov ah, [esi]这个可以试验一下,等出结果讨论由double改为long也是可以考虑一下谢谢大家
      

  14.   

    如果你可以用int(三十二位)作为循环内累加的变量的话,那么对于你的情况实际上用会编写还可以更快一点,因为对于编译器来说,for循环很可能是被解释成类似如下的汇编:
    mov ecx, 0
    jmp loop_cmp:
    loop_entry:
    ; bra bra bra of the codes in the looploop_cmp:
    cmp ecx, 12345678h
    jl  loop_entry:如果是编译成Native的,那么还有可能被编译器优化成其他形式。(我没仔细研究过,直觉告诉我不太可能会优化成其他形式。)如果你是用C#写的,或者VC.NET写的managed,那么就是编译成IL,那么我可以肯定就是这种jmp...jl的形式。(应该说是br...blt的形式。)这种方式显然不是最优化的,最优化的应该是如下这样的汇编:mov ecx, 12345678h   ; 设置循环次数
    lds esi, _The_thing_you_want_to_count_for  ; 设置开始位置这样的好处是避免了条件转xor edx, edx         ; 清除临时变量,实际上是想清除他的高位部分。
    ; 这里应该还有一句clX还是stX(X是什么忘了)的语句,用于设置esi的改变方向(递增还是递减)
    loop_entry:
    mov dl, [esi]     ; 获取一个子节
    add eax, edx      ; 累加到eax当中,因为edx高位为零,这里进行了一个隐藏的位长转换。
    loop loop_entry:  ; 循环移,虽然loop也是一种条件转移,但是相对于jxx来说,CPU对这个指令的分支预测显然要准确的多。那个类加器用32位的就够了,即使对于300万像素的也够了,300W * 256 = 3M * 256 = 768M,long的空间是-2G~2G,如果还觉得不保险的话,可以用uint,那就变成0~4G空间了。4G/256 = 16777216 = 1677.7W,现有的以及可以预见将来的摄像机也不太可能达到这个级别吧?用超过CPU数据处理长度的类型比如long(64位,对应于VC.NET的__int64)会明显降低速度的。此外,就算你不用一层循环做,那么也要明白a[0]...a[1]...a[2]...a+=3这样的做法是在浪费运算能力——这个体现在a+=3上面,实际上你只要把里面那一层的循环结束条件乘以3,然后改成a+=*b++就行了,能够节省你的运算。还有,我要提醒你的是,这里我提到的优化都只能够是争分夺秒,比如从1.8s变成1.7s,甚至只是1.795s。当然,从double改成long会有一个飞跃,从long改成int应该也会有一定提高,但是诸如用汇编、a+=*b++等,效果就不明显了。如果你是用C#或者managed C++,那么我建议你改用unmanaged C++,这样肯定能提高不少。
      

  15.   

    再补充一下:如果你是要把几个图片拼到一块,那么很有可能会超过1677.7W像素的,那么这个时候我建议你也不要用long,因为一个long会被分解成两个(甚至两个以上的)int操作——至少对于32位的CPU就是这样的,如果一次int操作要花费:(假设CPU内频1GHz,能同时执行8条指令)
    t = 1s / 1G / 8
    那么1677.7W个多出来的int操作就花费:
    1677W * t = 16.77M * 1s / 1000M / 8 = 0.002s照这么算,实际上如果你的CPU真能够达到一个周期同时执行8条指令的话,那么我估计做一次这样的运算总共也不可能超过0.1秒。也就是说估计会影响2%的效率,如果你真要争分夺秒的话对这个问题做优化是值得的,而且是很简单的。那么怎么做呢?你可以在每一个图片里面用int,图片间的相加用long,或者如果你要处理的是一个已经合成了的图片,那么在里面那个循环用int,外面那个循环再做一次long累加。
      

  16.   

    另外,如果可以的话,也许还可以通过SIMD汇编指令提高速度,不过这个SIMD我没用过也不知道怎么用,你到汇编的版块去问吧,如果需要的话。什么?什么是SIMD?Single Instrument Multi Data,单指令多数据。就是什么MMX/SSE/3d now之类的东西。此外上面有人提到的并行计算,我想如果你不是用大型机或者几个CPU,那是没有意义的——你根本就没有额外的资源让你可以并行计算,如果硬来肯定要通过模拟,这样只可能降速。而矩阵运算也是不切实际的,除非你用向量计算机,而我们用的Intel/Amd等都是标量计算机,根本就没有矩阵运算之类的功能。开多个线程也不行,因为你只有一个CPU,任意一个时间片你也只能够执行一个线程,多开线程只会意味着多出更多的线程调度事件。哦,有人说HyperThreading,这种CPU是否真算作有两个CPU也不讨论了,就当他有两个CPU好了,那么你开两个以上的线程还不是在浪费CPU?别忘了,除了你的这个Thread之外还有别的Process的Thread,实际上开两个Thread也是多余的!多线程不可能加快你的运算速度,多线程不是用于这方面的!上面还有人提到提高Thread的优先级,这个建议想法是对的,可是说错了,应该是提高Process的优先级。此外提高了对于速度的提高不会有太大的帮助,他的最大帮助是避免实际上不紧急的别的程序打断你的工作。另外我再看了一下你的那个“可能要跳转”的地方,琢磨着是不是你发现MSDN对于DIBSection里面的描述有类似这样的一句话:扫描线是双字(四字节)对齐的,如果一条扫描线的字节数不能被4整除,那么需要早最后填充无用字节以实现双字对齐。于是你就在程序里面做出如下的调整:
    nOffset = 4 - nWidth;
    for..
    {
      for..
      {
        a+=*b++;
      }
      nStart += nOffset;    // 我对于你的程序前面pMT += 3而又在这里
      // pMT = (nWidth+Offset)*3 表示怀疑,这样岂不是相当于跳过了一行?
    }如果是为了这样,那我建议你不用试图跳过这些填充字节,而是把这些字节也进行累加。因为填充字节都是零,因此应该是无害的,加指令可比条件跳转要快多了。
    另外再多说一句,a*3 写成 (a << 1) + a,应该会快一点点。
      

  17.   

    强烈赞成  sumtec(Psydian) 附加:
    C# 也同样可以使用指针,不必用 C++ 来实现。public unsafe static int SumIntArray(int[] src, int start, int length)
    {
         // 参数检查略
         ....
         
         // 
         int n = 0;
         fixed(int* pSrc = src)
         {
              int* ps = pSrc + start;
              int* pe = pSrc + start + length
              while (ps < pe)      
              {
                   n += *ps
                   ps++;
              }
         }
         return n;
    }
    //(以上代码未经测试)C# 编译器编译以上 C# 代码至 IL 代码和 .NET CLR 编译 IL 代码至 Native 代码,这些过程中会发生什么变化,我不清楚,究竟能比托管代码快多少,我未曾测试研究过。这是一个值得探讨的话题。
    但托管代码比非托管代码性能就一定差,这个结论至今我还未得到一个绝对的肯定。
      

  18.   

    我测试了一下,托管与非托管之间性能基本无差别。
    以下是测试代码,可能有不妥之处,请指正。
    using System;namespace Test
    {
    public class Class1
    {
    static void Main()
    {
    int[] intArray = new int[1000000];
    for (int i = 0; i < intArray.Length; i++)
    intArray[i] = i;

    int u, m;
    long startTicks, tick1, tick2;

    for (int j = 0; j < 10; j++)
    {
    startTicks = DateTime.Now.Ticks;
    u = Sum_Unsafe(intArray, 0, 1000000);
    tick1 = DateTime.Now.Ticks - startTicks;

    startTicks = DateTime.Now.Ticks;
    m = Sum_Managed(intArray, 0, 1000000);
    tick2 = DateTime.Now.Ticks - startTicks;

    Console.WriteLine("Test " + j.ToString());
    Console.WriteLine("Method Unsafe:" + u.ToString());
    Console.WriteLine("Taken Ticks:" + tick1.ToString());
    Console.WriteLine();
    Console.WriteLine("Method Managed:" + m.ToString());
    Console.WriteLine("Taken Ticks:" + tick2.ToString());
    Console.WriteLine("====================================");
    }
    }
    public unsafe static int Sum_Unsafe(int[] src, int start, int length)
    {
    // 参数检查略
    //.... int n = 0;
    fixed(int* pSrc = src)
    {
    int* ps = pSrc + start;
    int* pe = pSrc + start + length;
    while (ps < pe)      
    {
    n += *ps;
    ps++;
    }
    }
    return n;
    } public static int Sum_Managed(int[] src, int start, int length)
    {
    int n = 0;
    for (int i = 0; i < length; i++)
    {
    n += src[start+i];
    }
    return n;
    }
    }
    }
      

  19.   

    按照sumtec(Psydian) 改为32位的提议,也就是把double型的数据类型在累加中由uint替代,在作乘法和除法时才转为double的方法
    速度从以前的1.36s提高到了0.198788114131824s离希望的目标还是有点距离,可能只能靠其它的俩调整了在静态的图片中,也就是我不必要考虑太多模糊运算的前提下,我采用了先检查起始部分的匹配相识性,如果相识,再检测其它的部分的处理方式,(也就是最大限度地减少了频繁的累加运算)速度为0.0297881434651611s 谢谢sumtec(Psydian) 的大力帮助,问题分析得很彻底,非常有帮助
      

  20.   

    To AhBian(阿扁):对于托管和非托管的效率区别有多大,我也不确定,甚至是否有区别我都不确定,但我直觉认为是有区别的。不过你的测试方法是错误的,因为用Il的和Il转换成Native的比较是没有意义的,那并不是我说的托管和非托管的意思,我所说的应该是PCode和NativeCode的意思。因为从PCode转换成NativeCode本身就肯定会有效率损失,所以直接编译NativeCode应该会更加快一点。比如你会经常看到IL里面会有类似:
    call   System.Int32 function1(void)
    stloc.3
    ldloc.3
    这样的句子,也许在翻译成NativeCode就变成了:
    call function1
    push ax
    pop  ax
    而实际上后面两句话根本就是多余的。我说的效率损失就是这个含义,而不是翻译本身所带来的。也就是说,你用NGen这样的工具只能够提高程序装入速度或者第一次运行的速度,而不会提高你的实际运行效率。如果你要实验我所说的区别,那么就应该用C#写一个程序,然后用VC.NET写一个一模一样的unmanaged程序,然后再作比较。
    To cellblue:
    你现在的思路就对了:减少不必要的运算,或者提前做出运算,或者空间换时间,这些才是提高效率的关键,光是依靠工具还有double->int这样的方式是达不到你的目的的。如果你这里面可能会对某一个图片(或者某个图片的某一部分)进行重复分析,那么你就需要考虑可不可以将这些计算结果保存下来,避免重复的结果相同的计算了。
      

  21.   

    如果数组里面的数据变化不频繁,而针对数组的求和很频繁,那么不妨这样:
    源数据保存在A[1000]中,则创建另一数组B[1000],B里面的B[n]是A数组中A[n]和前面所有数的和。例如:
    B[0]=A[0]
    B[1]=A[0]+A[1]
    B[2]=A[0]+A[1]+A[2]
    以此类推。当然对A进行初始化的时候,就可以一边对A赋值,一边在临时变量中进行累加,把每次累加的值就放入B数组的相应位置。
    有了数组B后,要算A的从M到N的累加和,只要用B[N]-B[M-1]即可。做算法应该把思路打开,不要局限在表面的框框里,而应该跳出圈子。
      

  22.   

    如果数组里面的数据变化不频繁,而针对数组的求和很频繁,那么不妨这样:
    源数据保存在A[1000]中,则创建另一数组B[1000],B里面的B[n]是A数组中A[n]和前面所有数的和。例如:
    B[0]=A[0]
    B[1]=A[0]+A[1]
    B[2]=A[0]+A[1]+A[2]
    以此类推。当然对A进行初始化的时候,就可以一边对A赋值,一边在临时变量中进行累加,把每次累加的值就放入B数组的相应位置。
    有了数组B后,要算A的从M到N的累加和,只要用B[N]-B[M-1]即可。做算法应该把思路打开,不要局限在表面的框框里,而应该跳出圈子。
      

  23.   

    呵呵,一不小心发现前面有一个地方的分析好像出了点差错:300W个象素应该有900W个Byte,因为每个Pixel有3种颜色,900W个Byte累加起来的最大值应该是:
    9M * 255(原来个值也是不准确的) =  2295M = 2.3G。所以估计也就能够承受500W左右的像素,600W的有点悬。呵呵,有人提出B[x]-B[y]的方法,这个是一个不错的建议,前提你需要进行超过一次的完全求和过程。当然,这也是一个空间换时间的办法。如果有300W的像素,那么就会额外增加9M的空间。
      

  24.   

    我认为,对于汇编层来说,加法运算已经是不可再分的原子运算了,无论怎么优化,都快不到哪去。那么至少一次用循环作加法是必然发生的,问题是选择在什么时候进行。如果数据是相对固定的,而求和是频繁的,那么CPPBuilderExpert(流金岁月)的做法几乎是最直接的方法,其它方法无法做到比这个方法更快,所需的代价就是大批数据在加载时额外与临时变量做一个相加,使数据加载的速度慢一倍多。
      

  25.   

    谢谢大家的支持,这里的特点是数据产生很频繁,而且多数数据使用一次过后就不会再次使用现在我再调试一下B[x]-B[y]的方法
      

  26.   

    B[x]-B[y]的方法的要领是,在生成原始数组的过程中,同时顺带就把辅助数组的数据生成好了,这样将非常省CPU。不要等到原始数组完全初始化完成后再计算辅助数组。
      

  27.   

    ◢█〓★发布CSDN浏览器(免费)〓★█◣
             ◥◣◣◣★◢◢◢◤
                ◣★◥◤★◢
                   ◣★◢
                    ◥◤
                     ★欢迎大家对我的作品提出宝贵意见,并在此感谢项有建版主的支持。下载(项有建网站):http://www.338888.com/PumpCSDN.rar
    讨论:http://expert.csdn.net/Expert/TopicView1.asp?id=2445039用我的这款浏览器,能够轻而易举的实现每天定时自动登录所有用户。方法是,把CSDN浏览器可执行文件加入到Win2000的计划列表中,并在命令行参数中加入-l就可以按照规定的时间登陆了。如果CSDN浏览器开着,则直接点击工具条上面的笑脸按钮即可。
    该款浏览器有很多特性:
    1、主工具条可以停靠在不同的地方;发帖面板能够停靠在不同的地方,并能够自动隐藏
    2、具有帖子地址收藏功能;
    3、自动登录所有用户功能;
    4、通过链接托拽,创建不同CSDN论坛的快捷页面;
    5、页面自动登录;
    6、常用文字可收藏到仓库中,用时直接双击拷贝;
    7、多文档的模式打开多个的帖子,并能后台打开;
    8、多用户无缝切换发言(这对某些人来说,可能是最重要的)。注意事项,如果是老用户,可以用该版本覆盖原有版本的exe文件进行升级,但必须在原版本目录下手动删除CSDN_TB.ini和Layout.ini两个配置文件,否则工具条不会更新。
      

  28.   

    我看过 unix 中 tcp 协议求累加和的源代码,也就是直接循环累加。写 unix 的人都没什么好办法,估计应该没有了吧。
      

  29.   

    B[x]-B[y]的方法我可能无法用到,因为摄像机并不是我们生产的,因此我们无法从最原始的数据开始处理
    根据我的测试,单纯做一次累加运算,需要0.0310156737797681s由于会溢出,因此我测试了一下一个较小的图片
    累加到ulong
                   0.000269028605590934s
    累加到uint
                   0.00000159238115458808          1.59238115458808E-05s然而,这里头只能为long型,因此速度问题还是有限制
      

  30.   

    我已经提到过了,如果uint会溢出,那么可以在外层循环进行ulong累加,而内层循环则继续使用uint累加。比如:ulong sum;
    int   tempsum;sum = 0;
    for (int i ...)
    {
       tempsum = 0;
       for (int j...)
       {
          tempsum += ...;
       }
       sum += tempsum;
    }这样会比你直接用ulong快很多。关于.NET 托管语言的低层次优化,这里有一篇文章:
    http://www.microsoft.com/china/msdn/library/dndotnet/html/fastmanagedcode.asp你可以看到long和int之间的差别。
    此外,即使你无法从最原始的数据开始积累,如果你是多次需要使用其中的数据的话,你仍然可以使用B[y]-B[x]的思想:你可以判断是否已经产生过B[]数组,如果没有就转到顺便产生这个树组的那个循环块,如果已经产生了,那么就直接计算B[y]-B[x]。也许你在第一次进行累加计算的时候可能会额外负担0.01s的时间,但是以后每次运算就只需要不超过10ns的时间了。这样仍然是很划算的一件事情。
      

  31.   

    ulong dSigmaTemp = 0;
    ulong[] ulMBM = new ulong[lMWidth * lMHeight];for(m=0;m<lMHeight;m++)
    {
    for(n=0;n<lMWidth;n++)
    {
    dSigmaTemp += (uint)*pMT;
    pMT++;
    dSigmaTemp += (uint)*pMT;
    pMT++;
    dSigmaTemp += (uint)*pMT;
    pMT++; ulMBM[m * lMWidth + n] = dSigmaTemp; }
    pMT += nOffset;
    }
    类似于这样的结构,好像还不好改为sumtec(Psydian) 所说的那个
      

  32.   

    想你这样的问题似乎确实不太好改,不过还是可以进行修正的:
    ulong dSigmaTemp = 0;
    ulong[] ulMBM = new ulong[lMWidth * lMHeight];
    uint k;
    ushort tmpk = 0;
    for(m=0;m<lMHeight;m++)
    {
    for(n=0;n<lMWidth;n++)
    {
    tmp = *pMT; // 在这里(uint)强制转换是没有意义的,甚至会引起副作用
    pMT++;      // 因为最终还要变换到(ulong)上面,如果pMT是byte*的话
    tmp += *pMT;// 不过我这里是变换到(ushort)
    pMT++;
    dSigmaTemp += tmp + *pMT;
    pMT++;
    ulMBM[k++] = dSigmaTemp; // 这里你用了表达式运算,实际上是不需要的
    // 稍微分析一下就知道,你这里是顺序填充,只要不断增加索引就行了。
    }
    pMT += nOffset;
    }
    甚至实际上那个ulMBM[k++]也可以用ulong指针代替,也许会有那么一点点的速度提高。此外,请你告诉我那个pMT += nOffset的作用是什么?是用来察看一个“窗口”呢?还是用来强制双字对齐呢?
      

  33.   

    妙,确实可以提高点速度
    在这里,pMT += nOffset的作用是让本道程序符合于不同的图象格式,针对BitMap等,nOffset都等于0,针对其它的,有存在nOffset不为零的,也就是强制双字对齐谢谢
      

  34.   

    cellblue(cellblue)和sumtec(Psydian)水平真是高手之间过招,我看了半天暂时还没看出门道。我得好好学习。
      

  35.   

    哦,如果是这样的话,我会首先考虑:if (nOffset == 0)
    {
        for(...)
        {
        }
    }
    else
    {
        for(...)
        {
            for(...)
            {
            }
            p += nOffset;
        }
    }不过这样的优化已经有点变态了。