精华内容
下载资源
问答
  • 日常工作中,我们经常要用到多条件求和,方法有多种,第一类:使用基本功能来实现。主要有:筛选、分类汇总、数据透视表、多条件求和向导;第二类:使用公式来实现方法。主要有:使用SUM函数编写的数组公式、联用...
    日常工作中,我们经常要用到多条件求和,方法有多种,第一类:使用基本功能来实现。主要有:筛选、分类汇总、数据透视表、多条件求和向导;第二类:使用公式来实现方法。主要有:使用SUM函数编写的数组公式、联用SUMIF和辅助列(将多条件变为单条件)、使用SUMPRODUCT函数、使用SUMIFS函数(限于Excel2007及以上的版本),方法千差万别、效果各有千秋。本人更喜欢用SUMPRODUCT函数。由于Excel帮助对SUMPRODUCT函数的解释太简短了,与SUMPRODUCT函数的作用相比实在不匹配,为了更好地掌握该函数,特将其整理如下。

    龙逸凡注:欢迎转贴,但请注明作者及出处。

    一、         基本用法

    在给定的几组数组中,将数组间对应的元素相乘,并返回乘积之和。

    语法:

    SUMPRODUCT(array1,array2,array3, ...)

    Array1, array2, array3, ... 为 2 到 30 个数组,其相应元素需要进行相乘并求和。

    公式:=SUMPRODUCT(A2:B4, C2:D4)

            A        B        C        D
    1        Array 1        Array 1        Array 2        Array 2
    2        3        4        2        7
    3        8        6        6        7
    4        1        9        5        3
                                   

    公式解释:两个数组的所有元素对应相乘,然后把乘积相加,即 3*2 + 4*7 + 8*6 + 6*7 + 1*5 + 9*3。计算结果为156

    二、         扩展用法

    1、   使用SUMPRODUCT进行多条件计数

    语法:

    =SUMPRODUCT((条件1)*(条件2)*(条件3)* …(条件n))

    作用:

    统计同时满足条件1、条件2到条件n的记录的个数。

    实例:

    =SUMPRODUCT((A2:A10="男")*(B2:B10="中级职称"))

    公式解释:

    统计性别为男性且职称为中级职称的职工的人数

    2、   使用SUMPRODUCT进行多条件求和

    语法:

    =SUMPRODUCT((条件1)*(条件2)* (条件3) *…(条件n)*某区域)

    作用:

    汇总同时满足条件1、条件2到条件n的记录指定区域的汇总金额。

    实例:

    =SUMPRODUCT((A2:A10="男")*(B2:B10="中级职称")*C2:C10)

    公式解释:

    统计性别为男性且职称为中级职称的职工的工资总和(假设C列为工资)

    三、         注意事项

    1、数组参数必须具有相同的维数,否则,函数 SUMPRODUCT 将返回错误值 #VALUE!。

    2、SUMPRODUCT函数将非数值型的数组元素作为 0 处理。

    3、在SUMPRODUCT中,2003及以下版本不支持整列(行)引用,必须指明范围,不可在SUMPRODUCT函数使用A:A、B:B,Excel2007及以上版本可以整列(列)引用,但并不建议如此使用,公式计算速度慢。

    4、SUMPRODUCT函数不支持“*”和“?”通配符

    SUMPRODUCT函数不能象SUMIF、COUNTIF等函数一样使用“*”和“?”等通配符,要实现此功能可以用变通的方法,如使用LEFT、RIGHT、ISNUMBER(FIND())或ISNUMBER(SEARCH())等函数来实现通配符的功能。如:

    =SUMPRODUCT((A2:A10="男")*(B2:B10="中级职称")*(LEFT(D2:D10,1)="龙")*C2:C10)

    =SUMPRODUCT((A2:A10="男")*(B2:B10="中级职称")*((ISNUMBER(FIND("龙逸凡",D2:D10)))*C2:C10))

    注:以上公式假设D列为职工姓名。ISNUMBER(FIND())、ISNUMBER(SEARCH())作用是实现“*”的通配功能,只是前者区分大小写,后者不区分大小写。

    5、SUMPRODUCT函数多条件求和时使用“,”和“*”的区别:当拟求和的区域中无文本时两者无区别,当有文本时,使用“*”时会出错,返回错误值 #VALUE!,而使用“,”时SUMPRODUCT函数会将非数值型的数组元素作为 0 处理,故不会报错。 也就是说:

    公式1:=SUMPRODUCT((A2:A10="男")*(B2:B10="中级职称")*C2:C10)

    公式2:=SUMPRODUCT((A2:A10="男")*(B2:B10="中级职称"),C2:C10)

    当C2:C10中全为数值时,两者计算结果一样,当C2:C10中有文本时公式1会返回错误值 #VALUE!,而公式2会返回忽略文本以后的结果。

    四、         网友们的精彩实例

    1、求指定区域的奇数列的数值之和

    =SUMPRODUCT(MOD(COLUMN(A1:F1),2)*A1:F1)

    2、求指定区域的偶数行的数值之和

    =SUMPRODUCT(((MOD(ROW(A1:A22),2))-1)*A1:A22)*(-1)

    3、求指定行中列号能被4整除的列的数值之和  

    =SUMPRODUCT((MOD(COLUMN(A1:P1),4)=0)*A1:P1)

    4、.求某数值列前三名分数之和

    =SUMPRODUCT(LARGE(B1:B16,ROW(1:3)))

    5、统计指定区域不重复记录的个数

    =SUMPRODUCT(1/COUNTIF(V11:V15,V11:V15))

    展开全文
  • 解析mysql不重复字段值求和 本篇文章是对关于mysql不重复字段值求和进行了详细的分析介绍,需要的朋友参考下 在使用mysql时,有时需要查询出某个字段不重复的记录,虽然mysql提供有distinct这个关键字...

    解析mysql不重复字段值求和

    本篇文章是对关于mysql不重复字段值求和进行了详细的分析介绍,需要的朋友参考下

    在使用mysql时,有时需要查询出某个字段不重复的记录,虽然mysql提供有distinct这个关键字来过滤掉多余的重复记录只保留一条,但往往只用它来返回不重复记录的条数,而不是用它来返回不重记录的所有值。其原因是distinct只能返回它的目标字段,而无法返回其它字段,这个问题让我困扰了很久,用distinct不能解决的话,我只有用二重循环查询来解决,而这样对于一个数据量非常大的站来说,无疑是会直接影响到效率的。所以我花了很多时间来研究这个问题,网上也查不到解决方案。。
    下面先来看看例子:
    table
    id name
    1 a
    2 b
    3 c
    4 c
    5 b
    库结构大概这样,这只是一个简单的例子,实际情况会复杂得多。
    比如我想用一条语句查询得到name不重复的所有数据,那就必须使用distinct去掉多余的重复记录。
    select distinct name from table
    得到的结果是:
    name
    a

    c
    好像达到效果了,可是,我想要得到的是id值呢?改一下查询语句吧:
    select distinct name, id from table
    结果会是:
    id name
    1 a
    2 b
    3 c
    4 c
    5 b
    distinct怎么没起作用?作用是起了的,不过他同时作用了两个字段,也就是必须得id与name都相同的才会被排除。。。。。。。
    我们再改改查询语句:
    select id, distinct name from table
    很遗憾,除了错误信息你什么也得不到,distinct必须放在开头。难到不能把distinct放到where条件里?能,照样报错。。。。。。。
    很麻烦吧?确实,费尽心思都没能解决这个问题。没办法,继续找人问。
    拉住公司里一JAVA程序员,他给我演示了oracle里使用distinct之后,也没找到mysql里的解决方案,最后下班之前他建议我试试group by。
    试了半天,也不行,最后在mysql手册里找到一个用法,用group_concat(distinct name)配合group by name实现了我所需要的功能,兴奋,天佑我也,赶快试试。
    报错。。。。。。。。。。。。郁闷。。。。。。。连mysql手册也跟我过不去,先给了我希望,然后又把我推向失望,好狠哪。。。。
    再仔细一查,group_concat函数是4.1支持,晕,我4.0的。没办法,升级,升完级一试,成功。。。。。。
    终于搞定了,不过这样一来,又必须要求客户也升级了。
    突然灵机一闪,既然可以使用group_concat函数,那其它函数能行吗?
    赶紧用count函数一试,成功,我。。。。。。。想哭啊,费了这么多工夫。。。。。。。。原来就这么简单。。。。。。
    现在将完整语句放出:
    select *, count(distinct name) from table group by name
    结果:
    id name count(distinct name)
    1 a 1
    2 b 1
    3 c 1
    最后一项是多余的,不用管就行了,目的达到。。。。。
    唉,原来mysql这么笨,轻轻一下就把他骗过去了,郁闷也就我吧,现在拿出来希望大家不要被这问题折腾。
    哦,对,再顺便说一句,group by 必须放在 order by 和 limit之前,不然会报错,差不多了,我继续忙碌。。。。。。

    展开全文
  • (转)Intrinsic—使用SSE、AVX指令集处理单精度浮点数组求和(支持vc、gcc,兼容Win、Linux、Mac) ...[C] 跨平台使用Intrinsic函数范例1——使用SSE、AVX指令集 处理 单精度浮点数组求和(支持vc、gcc

    这篇文章写的非常好,特别是文中的链接也要仔细浏览。

    ======================================


    (转)Intrinsic—使用SSE、AVX指令集处理单精度浮点数组求和(支持vc、gcc,兼容Win、Linux、Mac)

     (2013-01-14 10:45:16)
    标签: 

    杂谈

    分类: 汇编
    [C] 跨平台使用Intrinsic函数范例1——使用SSE、AVX指令集 处理 单精度浮点数组求和(支持vc、gcc,兼容Windows、Linux、Mac)
    !!
    http://www.cnblogs.com/zyl910/archive/2012/10/22/simdsumfloat.html

    本文面对对SSE等SIMD指令集有一定基础的读者,以单精度浮点数组求和为例演示了如何跨平台使用SSE、AVX指令集。因使用了stdint、 zintrin、ccpuid这三个模块,可以完全避免手工编写汇编代码,具有很高可移植性。支持vc、gcc编译器,在Windows、Linux、 Mac这三大平台上成功运行。


    一、问题背景

      最初,我们只能使用汇编语言来编写SIMD代码。不仅写起来很麻烦,而且易读性、可维护性、移植性都较差。
      不久,VC、GCC等编译器相继支持了Intrinsic函数,使我们可以摆脱汇编,利用C语言来调用SIMD指令集,大大提高了易读性和可维护。而且移植性也有提高,能在同一编译器上实现32位与64位的平滑过渡。
      但当代码在另一种编译器编译时,会遇到一些问题而无法编译。甚至在使用同一种编译器的不同版本时,也会遇到无法编译问题。

      首先是整数类型问题——
      传统C语言的short、int、long等整数类型是与平台相关的,不同平台上的位长是不同的(例如 Windows是LLP64模型,Linux、Mac等Unix系统多采用LP64模型)。而使用SSE等SIMD指令集时需要精确计算数据的位数,不同 位长的数据必须使用不同的指令来处理。
      有一个解决办法,就是使用C99标准中stdint.h所提供的指定位长的整数类型。GCC对C99标准支持性较好,而VC的步骤很慢,貌似直到VC2010才支持stdint.h。而很多时候我们为了兼容旧代码,不得不使用VC6等老版本的VC编译器。

      其次是Intrinsic函数的头文件问题,不同编译器所使用的头文件不同——
      对于早期版本VC,需要根据具体的指令集需求,手动引入mmintrin.h、xmmintrin.h等头文件。对于VC2005或更高版本,引入intrin.h就行了,它会自动引入当前编译器所支持的所有Intrinsic头文件。
      对于早期版本GCC,也是手动引入mmintrin.h、xmmintrin.h等头文件。而对于高版本的GCC,引入x86intrin.h就行了,它会自动引入当前编译环境所允许的Intrinsic头文件。

      再次是当前编译环境下的Intrinsic函数集支持性问题——
      对于VC来说,VC6支持MMX、3DNow!、SSE、 SSE2,然后更高版本的VC支持更多的指令集。但是,VC没有提供检测Intrinsic函数集支持性的办法。例如你在VC2010上编写了一段使用了 AVX Intrinsic函数的代码,但拿到VC2005上就不能通过编译了。其次,VC不支持64位下的MMX,这让一些老程序迁徙到64位版时遭来了一些麻 烦。
      而对于GCC来说,它使用-mmmx、-msse等编译器开关来启用各种指令集,同时定义了对应的 __MMX__、__SSE__等宏,然后x86intrin.h会根据这些宏来声明相应的Intrinsic函数集。__MMX__、__SSE__等 宏可以帮助我们判断Intrinsic函数集是否支持,但这只是GCC的专用功能。
      此外还有一些细节问题,例如某些Intrinsic函数仅在64下才能使用、有些老版本编译器的头文件缺少某个Intrinsic函数。所以我们希望有一种统一的方式来判断Intrinsic函数集的支持性。

      除了编译期间的问题外,还有运行期间的问题——
      在运行时,怎么检测当前处理器支持哪些指令集?
      虽然X86体系提供了用来检测处理器的CPUID指令,但它没有规范的Intrinsic函数,在不同的编译器上的用法不同。
      而且X86体系有很多种指令集,每种指令集具体的检测方法是略有区别的。尤其是SSE、AVX这样的SIMD指令集是需要操作系统配合才能正常使用的,所以在CPUID检查通过后,还需要进一步验证。


    二、范例讲解

    2.1 事先准备

      为了解决上面提到的问题,我编写了三个模块——
    stdint:智能支持C99的stdint.h,解决整数类型问题。最新版的地址是http://www.cnblogs.com/zyl910/archive/2012/08/08/c99int.html 。
    zintrin:在编译时检测Intrinsic函数集支持性,并自动引入相关头文件、修正细节问题。最新版的地址是http://www.cnblogs.com/zyl910/archive/2012/10/01/zintrin_v101.html 。
    ccpuid:在编译时检测指令集的支持性。最新版的地址是http://www.cnblogs.com/zyl910/archive/2012/10/13/ccpuid_v103.html 。

      这三个模块的纯C版就是一个头文件,用起来很方便,将它们放在项目中,直接#include就行了。例如——

    #define __STDC_LIMIT_MACROS 1 // C99整数范围常量. [纯C程序可以不用, 而C++程序必须定义该宏.]#include "zintrin.h" #include "ccpuid.h"

     

      因为stdint.h会被zintrin.h或ccpuid.h引用,所以不需要手动引入它。
      因为它们用到了C99整数范围常量,所以应该在程序的最前面定义__STDC_LIMIT_MACROS宏(或者可以在项目配置、编译器命令行等位置进行配置)。根据C99规范,纯C程序可以不用, 而C++程序必须定义该宏。本文为了演示,定义了该宏。


    2.2 C语言版

      我们先用C语言编写一个基本的单精度浮点数组求和函数——

    // 单精度浮点数组求和_基本版.
    //
    // result: 返回数组求和结果.
    // pbuf: 数组的首地址.
    // cntbuf: 数组长度.
    float sumfloat_base(const float* pbuf, size_t cntbuf)
    {
        float s = 0;    // 求和变量.
        size_t i;
        for(i=0; i
        {
            s += pbuf[i];
        }
        return s;
    }

    该函数很容易理解——先将返回值赋初值0,然后循环加上数组中每一项的值。


    2.3 SSE版

    2.3.1 SSE普通版

      SSE寄存器是128位的,对应__m128类型,它能一次能处理4个单精度浮点数。
      很多SSE指令要求内存地址按16字节对齐。本文为了简化,假定浮点数组的首地址是总是16字节对齐的,仅需要考虑数组长度不是4的整数倍问题。
      因使用了SSE Intrinsic函数,我们可以根据zintrin.h所提供的INTRIN_SSE宏进行条件编译。
      代码如下——

    #ifdef INTRIN_SSE
    // 单精度浮点数组求和_SSE版.
    float sumfloat_sse(const float* pbuf, size_t cntbuf)
    {
        float s = 0;    // 求和变量.
        size_t i;
        size_t nBlockWidth = 4;    // 块宽. SSE寄存器能一次处理4个float.
        size_t cntBlock = cntbuf / nBlockWidth;    // 块数.
        size_t cntRem = cntbuf % nBlockWidth;    // 剩余数量.
        __m128 xfsSum = _mm_setzero_ps();    // 求和变量。[SSE] 赋初值0
        __m128 xfsLoad;    // 加载.
        const float* p = pbuf;    // SSE批量处理时所用的指针.
        const float* q;    // 将SSE变量上的多个数值合并时所用指针.

        // SSE批量处理.
        for(i=0; i
        {
            xfsLoad = _mm_load_ps(p);    // [SSE] 加载
            xfsSum = _mm_add_ps(xfsSum, xfsLoad);    // [SSE] 单精浮点紧缩加法
            p += nBlockWidth;
        }
        // 合并.
        q = (const float*)&xfsSum;
        s = q[0] + q[1] + q[2] + q[3];

        // 处理剩下的.
        for(i=0; i
        {
            s += p[i];
        }

        return s;
    }

    #endif    // #ifdef INTRIN_SSE

    上述代码大致可分为四个部分——
    1. 变量定义与初始化。
    2. SSE批量处理。即对前面能凑成4个一组的数据,利用SSE的128位宽度同时对4个数累加。
    3. 合并。将__m128上的多个数值合并到求和变量。因考虑某些编译器不能直接使用“.”来访问__m128变量中的数据,于是利用指针q来访问xfsSum中的数据。
    4. 处理剩下的。即对尾部不能凑成4个一组的数据,采用基本的逐项相加算法。

      上述代码总共用到了3个SSE Intrinsic函数——
    _mm_setzero_ps:对应XORPS指令。将__m128上的每一个单精度浮点数均赋0值,伪代码:for(i=0;i<4;++i) C[i]=0.0f。
    _mm_load_ps:对应MOVPS指令。从内存中对齐加载4个单精度浮点数到__m128变量,伪代码:for(i=0;i<4;++i) C[i]=_A[i]。
    _mm_add_ps:对应ADDPS指令。相加,即对2个__m128变量的4个单精度浮点数进行垂直相加,伪代码:for(i=0;i<4;++i) C[i]=A[i]+B[i]。


    2.3.2 SSE四路循环展开版

      循环展开可以降低循环开销,提高指令级并行性能。
      一般来说,四路循环展开就差不多够了。我们可以很方便的将上一节的代码改造为四路循环展开版——

    // 单精度浮点数组求和_SSE四路循环展开版.
    float sumfloat_sse_4loop(const float* pbuf, size_t cntbuf)
    {
        float s = 0;    // 返回值.
        size_t i;
        size_t nBlockWidth = 4*4;    // 块宽. SSE寄存器能一次处理4个float,然后循环展开4次.
        size_t cntBlock = cntbuf / nBlockWidth;    // 块数.
        size_t cntRem = cntbuf % nBlockWidth;    // 剩余数量.
        __m128 xfsSum = _mm_setzero_ps();    // 求和变量。[SSE] 赋初值0
        __m128 xfsSum1 = _mm_setzero_ps();
        __m128 xfsSum2 = _mm_setzero_ps();
        __m128 xfsSum3 = _mm_setzero_ps();
        __m128 xfsLoad;    // 加载.
        __m128 xfsLoad1;
        __m128 xfsLoad2;
        __m128 xfsLoad3;
        const float* p = pbuf;    // SSE批量处理时所用的指针.
        const float* q;    // 将SSE变量上的多个数值合并时所用指针.

        // SSE批量处理.
        for(i=0; i
        {
            xfsLoad = _mm_load_ps(p);    // [SSE] 加载.
            xfsLoad1 = _mm_load_ps(p+4);
            xfsLoad2 = _mm_load_ps(p+8);
            xfsLoad3 = _mm_load_ps(p+12);
            xfsSum = _mm_add_ps(xfsSum, xfsLoad);    // [SSE] 单精浮点紧缩加法
            xfsSum1 = _mm_add_ps(xfsSum1, xfsLoad1);
            xfsSum2 = _mm_add_ps(xfsSum2, xfsLoad2);
            xfsSum3 = _mm_add_ps(xfsSum3, xfsLoad3);
            p += nBlockWidth;
        }
        // 合并.
        xfsSum = _mm_add_ps(xfsSum, xfsSum1);    // 两两合并(0~1).
        xfsSum2 = _mm_add_ps(xfsSum2, xfsSum3);    // 两两合并(2~3).
        xfsSum = _mm_add_ps(xfsSum, xfsSum2);    // 两两合并(0~3).
        q = (const float*)&xfsSum;
        s = q[0] + q[1] + q[2] + q[3];

        // 处理剩下的.
        for(i=0; i
        {
            s += p[i];
        }

        return s;
    }

    2.4 AVX版

    2.4.1 AVX普通版

      AVX寄存器是256位的,对应__m256类型,它能一次能处理8个单精度浮点数。
      很多AVX指令要求内存地址按32字节对齐。本文为了简化,假定浮点数组的首地址是总是32字节对齐的,仅需要考虑数组长度不是8的整数倍问题。
      因使用了AVX Intrinsic函数,我们可以根据zintrin.h所提供的INTRIN_AVX宏进行条件编译。

      代码如下——

    #ifdef INTRIN_AVX
    // 单精度浮点数组求和_AVX版.
    float sumfloat_avx(const float* pbuf, size_t cntbuf)
    {
        float s = 0;    // 求和变量.
        size_t i;
        size_t nBlockWidth = 8;    // 块宽. AVX寄存器能一次处理8个float.
        size_t cntBlock = cntbuf / nBlockWidth;    // 块数.
        size_t cntRem = cntbuf % nBlockWidth;    // 剩余数量.
        __m256 yfsSum = _mm256_setzero_ps();    // 求和变量。[AVX] 赋初值0
        __m256 yfsLoad;    // 加载.
        const float* p = pbuf;    // AVX批量处理时所用的指针.
        const float* q;    // 将AVX变量上的多个数值合并时所用指针.

        // AVX批量处理.
        for(i=0; i
        {
            yfsLoad = _mm256_load_ps(p);    // [AVX] 加载
            yfsSum = _mm256_add_ps(yfsSum, yfsLoad);    // [AVX] 单精浮点紧缩加法
            p += nBlockWidth;
        }
        // 合并.
        q = (const float*)&yfsSum;
        s = q[0] + q[1] + q[2] + q[3] + q[4] + q[5] + q[6] + q[7];

        // 处理剩下的.
        for(i=0; i
        {
            s += p[i];
        }

        return s;
    }

    #endif    // #ifdef INTRIN_AVX

    由上可见,将SSE Intrinsic代码(sumfloat_sse)升级为 AVX Intrinsic代码(sumfloat_avx)是很容易的——
    1. 升级数据类型,将__m128升级成了__m256。
    2. 升级Intrinsic函数,在函数名中加入255。例如_mm_setzero_ps、_mm_load_ps、_mm_add_ps,对应的AVX版函数是 _mm256_setzero_ps、_mm256_load_ps、_mm256_add_ps。
    3. 因位宽翻倍,地址计算与数据合并的代码需稍加改动。

      当使用VC2010编译含有AVX的代码时,VC会提醒你——
    warning C4752: 发现 Intel(R) 高级矢量扩展;请考虑使用 /arch:AVX

      目前“/arch:AVX”尚未整合到项目属性的“C++\代码生成\启用增强指令集”中,需要手动在项目属性的“C++\命令行”的附加选项中加上“/arch:AVX”——

    详见MSDN——
    http://msdn.microsoft.com/zh-cn/library/7t5yh4fd(v=vs.100).aspx
    在 Visual Studio 中设置 /arch:AVX 编译器选项
    1.打开项目的“属性页”对话框。 有关更多信息,请参见 如何:打开项目属性页。
    2.单击“C/C++”文件夹。
    3.单击“命令行”属性页。
    4.在“附加选项”框中添加 /arch:AVX。


    2.4.2 AVX四路循环展开版

      同样的,我们可以编写AVX四路循环展开版——

    // 单精度浮点数组求和_AVX四路循环展开版.
    float sumfloat_avx_4loop(const float* pbuf, size_t cntbuf)
    {
        float s = 0;    // 求和变量.
        size_t i;
        size_t nBlockWidth = 8*4;    // 块宽. AVX寄存器能一次处理8个float,然后循环展开4次.
        size_t cntBlock = cntbuf / nBlockWidth;    // 块数.
        size_t cntRem = cntbuf % nBlockWidth;    // 剩余数量.
        __m256 yfsSum = _mm256_setzero_ps();    // 求和变量。[AVX] 赋初值0
        __m256 yfsSum1 = _mm256_setzero_ps();
        __m256 yfsSum2 = _mm256_setzero_ps();
        __m256 yfsSum3 = _mm256_setzero_ps();
        __m256 yfsLoad;    // 加载.
        __m256 yfsLoad1;
        __m256 yfsLoad2;
        __m256 yfsLoad3;
        const float* p = pbuf;    // AVX批量处理时所用的指针.
        const float* q;    // 将AVX变量上的多个数值合并时所用指针.

        // AVX批量处理.
        for(i=0; i
        {
            yfsLoad = _mm256_load_ps(p);    // [AVX] 加载.
            yfsLoad1 = _mm256_load_ps(p+8);
            yfsLoad2 = _mm256_load_ps(p+16);
            yfsLoad3 = _mm256_load_ps(p+24);
            yfsSum = _mm256_add_ps(yfsSum, yfsLoad);    // [AVX] 单精浮点紧缩加法
            yfsSum1 = _mm256_add_ps(yfsSum1, yfsLoad1);
            yfsSum2 = _mm256_add_ps(yfsSum2, yfsLoad2);
            yfsSum3 = _mm256_add_ps(yfsSum3, yfsLoad3);
            p += nBlockWidth;
        }
        // 合并.
        yfsSum = _mm256_add_ps(yfsSum, yfsSum1);    // 两两合并(0~1).
        yfsSum2 = _mm256_add_ps(yfsSum2, yfsSum3);    // 两两合并(2~3).
        yfsSum = _mm256_add_ps(yfsSum, yfsSum2);    // 两两合并(0~3).
        q = (const float*)&yfsSum;
        s = q[0] + q[1] + q[2] + q[3] + q[4] + q[5] + q[6] + q[7];

        // 处理剩下的.
        for(i=0; i
        {
            s += p[i];
        }

        return s;
    }

    2.5 测试框架

    2.5.1 测试所用的数组

      首先考虑一下测试所用的数组的长度应该是多少比较好。
      为了避免内存带宽问题,这个数组最好能放在L1 Data Cache中。现在的处理器的L1 Data Cache一般是32KB,为了保险最好再除以2,那么数组的长度应该是 32KB/(2*sizeof(float))=4096。
      其次考虑内存对齐问题,avx要求32字节对齐。我们可以定义一个ATTR_ALIGN宏来统一处理变量的内存对齐问题。
      该数组定义如下——

    // 变量对齐.
    #ifndef ATTR_ALIGN
    #  if defined(__GNUC__)    // GCC
    #    define ATTR_ALIGN(n)    __attribute__((aligned(n)))
    #  else    // 否则使用VC格式.
    #    define ATTR_ALIGN(n)    __declspec(align(n))
    #  endif
    #endif    // #ifndef ATTR_ALIGN


    #define BUFSIZE    4096    // = 32KB{L1 Cache} / (2 * sizeof(float))
    ATTR_ALIGN(32) float buf[BUFSIZE];

    2.5.2 测试函数

      如果为每一个函数都编写一套测试代码,那不仅代码量大,而且不易维护。
      可以考虑利用函数指针来实现一套测试框架。
      因sumfloat_base等函数的签名是一致的,于是可以定义这样的一种函数指针——
    // 测试时的函数类型
    typedef float (*TESTPROC)(const float* pbuf, size_t cntbuf);

      然后再编写一个对TESTPROC函数指针进行测试的函数——

    // 进行测试
    void runTest(const char* szname, TESTPROC proc)
    {
        const int testloop = 4000;    // 重复运算几次延长时间,避免计时精度问题.
        const clock_t TIMEOUT = CLOCKS_PER_SEC/2;    // 最短测试时间.
        int i,j,k;
        clock_t    tm0, dt;    // 存储时间.
        double mps;    // M/s.
        double mps_good = 0;    // 最佳M/s. 因线程切换会导致的数值波动, 于是选取最佳值.
        volatile float n=0;    // 避免内循环被优化.
        for(i=1; i<=3; ++i)    // 多次测试.
        {
            tm0 = clock();
            // main
            k=0;
            do
            {
                for(j=1; j<=testloop; ++j)    // 重复运算几次延长时间,避免计时开销带来的影响.
                {
                    n = proc(buf, BUFSIZE);    // 避免内循环被编译优化消掉.
                }
                ++k;
                dt = clock() - tm0;
            }while(dt
            // show
            mps = (double)k*testloop*BUFSIZE*CLOCKS_PER_SEC/(1024.0*1024.0*dt);    // k*testloop*BUFSIZE/(1024.0*1024.0) 将数据规模换算为M,然后再乘以 CLOCKS_PER_SEC/dt 换算为M/s .
            if (mps_good
            //printf("%s:\t%.0f M/s\t//%f\n", szname, mps, n);
        }
        printf("%s:\t%.0f M/s\t//%f\n", szname, mps_good, n);
    }

     j是最内层的循环,负责多次调用TESTPROC函数指针。如果每调用一次TESTPROC函数指针后又调用clock函数,那会带来较大的计时开销,影响评测成绩。
      k循环负责检测超时。当发现超过预定时限,便计算mps,即每秒钟处理了多少百万个单精度浮点数。然后存储最佳的mps。
      i是最外层循环的循环变量,循环3次然后报告最佳值。


    2.5.3 进行测试

      在进行测试之前,需要对buf数组进行初始化,将数组元素赋随机值——

    // init buf
    srand( (unsigned)time( NULL ) );
    for (i = 0; i < BUFSIZE; i++) 
      buf[i] = (float)(rand() & 0x3f); // 使用&0x3f是为了让求和后的数值不会超过float类型的有效位数,便于观察结果是否正确.

     

      然后可以开始测试了——

    // test
        runTest("sumfloat_base", sumfloat_base);    // 单精度浮点数组求和_基本版.
    #ifdef INTRIN_SSE
        if (simd_sse_level(NULL) >= SIMD_SSE_1)
        {
            runTest("sumfloat_sse", sumfloat_sse);    // 单精度浮点数组求和_SSE版.
            runTest("sumfloat_sse_4loop", sumfloat_sse_4loop);    // 单精度浮点数组求和_SSE四路循环展开版.
        }
    #endif    // #ifdef INTRIN_SSE
    #ifdef INTRIN_AVX
        if (simd_avx_level(NULL) >= SIMD_AVX_1)
        {
            runTest("sumfloat_avx", sumfloat_avx);    // 单精度浮点数组求和_AVX版.
            runTest("sumfloat_avx_4loop", sumfloat_avx_4loop);    // 单精度浮点数组求和_AVX四路循环展开版.
        }
    #endif    // #ifdef INTRIN_AVX

     INTRIN_SSE、INTRIN_AVX 宏是 zintrin.h 提供的,用于在编译时检测编译器是否支持SSE、AVX指令集。
      simd_sse_level、simd_avx_level函数是 ccpuid.h 提供的,用于在运行时检测当前系统环境是否支持SSE、AVX指令集。


    2.6 杂项

      为了方便对比测试,可以在程序启动时显示程序版本、编译器名称、CPU型号信息。即在main函数中加上——

    char szBuf[64];
        int i;

        printf("simdsumfloat v1.00 (�it)\n", INTRIN_WORDSIZE);
        printf("Compiler: %s\n", COMPILER_NAME);
        cpu_getbrand(szBuf);
        printf("CPU:\t%s\n", szBuf);
        printf("\n");

      INTRIN_WORDSIZE 宏是 zintrin.h 提供的,为当前机器的字长。
      cpu_getbrand是 ccpuid.h 提供的,用于获得CPU型号字符串。
      COMPILER_NAME 是一个用来获得编译器名称的宏,它的详细定义是——

    // Compiler name
    #define MACTOSTR(x)    #x
    #define MACROVALUESTR(x)    MACTOSTR(x)
    #if defined(__ICL)    // Intel C++
    #  if defined(__VERSION__)
    #    define COMPILER_NAME    "Intel C++ " __VERSION__
    #  elif defined(__INTEL_COMPILER_BUILD_DATE)
    #    define COMPILER_NAME    "Intel C++ (" MACROVALUESTR(__INTEL_COMPILER_BUILD_DATE) ")"
    #  else
    #    define COMPILER_NAME    "Intel C++"
    #  endif    // #  if defined(__VERSION__)
    #elif defined(_MSC_VER)    // Microsoft VC++
    #  if defined(_MSC_FULL_VER)
    #    define COMPILER_NAME    "Microsoft VC++ (" MACROVALUESTR(_MSC_FULL_VER) ")"
    #  elif defined(_MSC_VER)
    #    define COMPILER_NAME    "Microsoft VC++ (" MACROVALUESTR(_MSC_VER) ")"
    #  else
    #    define COMPILER_NAME    "Microsoft VC++"
    #  endif    // #  if defined(_MSC_FULL_VER)
    #elif defined(__GNUC__)    // GCC
    #  if defined(__CYGWIN__)
    #    define COMPILER_NAME    "GCC(Cygmin) " __VERSION__
    #  elif defined(__MINGW32__)
    #    define COMPILER_NAME    "GCC(MinGW) " __VERSION__
    #  else
    #    define COMPILER_NAME    "GCC " __VERSION__
    #  endif    // #  if defined(_MSC_FULL_VER)
    #else
    #  define COMPILER_NAME    "Unknown Compiler"
    #endif    // #if defined(__ICL)    // Intel C++

    三、全部代码

    3.1 simdsumfloat.c

      全部代码——

    simdsumfloat.c

    #define __STDC_LIMIT_MACROS    1    // C99整数范围常量. [纯C程序可以不用, 而C++程序必须定义该宏.]

    #include
    #include
    #include

    #include "zintrin.h"
    #include "ccpuid.h"


    // Compiler name
    #define MACTOSTR(x)    #x
    #define MACROVALUESTR(x)    MACTOSTR(x)
    #if defined(__ICL)    // Intel C++
    #  if defined(__VERSION__)
    #    define COMPILER_NAME    "Intel C++ " __VERSION__
    #  elif defined(__INTEL_COMPILER_BUILD_DATE)
    #    define COMPILER_NAME    "Intel C++ (" MACROVALUESTR(__INTEL_COMPILER_BUILD_DATE) ")"
    #  else
    #    define COMPILER_NAME    "Intel C++"
    #  endif    // #  if defined(__VERSION__)
    #elif defined(_MSC_VER)    // Microsoft VC++
    #  if defined(_MSC_FULL_VER)
    #    define COMPILER_NAME    "Microsoft VC++ (" MACROVALUESTR(_MSC_FULL_VER) ")"
    #  elif defined(_MSC_VER)
    #    define COMPILER_NAME    "Microsoft VC++ (" MACROVALUESTR(_MSC_VER) ")"
    #  else
    #    define COMPILER_NAME    "Microsoft VC++"
    #  endif    // #  if defined(_MSC_FULL_VER)
    #elif defined(__GNUC__)    // GCC
    #  if defined(__CYGWIN__)
    #    define COMPILER_NAME    "GCC(Cygmin) " __VERSION__
    #  elif defined(__MINGW32__)
    #    define COMPILER_NAME    "GCC(MinGW) " __VERSION__
    #  else
    #    define COMPILER_NAME    "GCC " __VERSION__
    #  endif    // #  if defined(_MSC_FULL_VER)
    #else
    #  define COMPILER_NAME    "Unknown Compiler"
    #endif    // #if defined(__ICL)    // Intel C++


    //
    // sumfloat: 单精度浮点数组求和的函数
    //

    // 单精度浮点数组求和_基本版.
    //
    // result: 返回数组求和结果.
    // pbuf: 数组的首地址.
    // cntbuf: 数组长度.
    float sumfloat_base(const float* pbuf, size_t cntbuf)
    {
        float s = 0;    // 求和变量.
        size_t i;
        for(i=0; i
        {
            s += pbuf[i];
        }
        return s;
    }

    #ifdef INTRIN_SSE
    // 单精度浮点数组求和_SSE版.
    float sumfloat_sse(const float* pbuf, size_t cntbuf)
    {
        float s = 0;    // 求和变量.
        size_t i;
        size_t nBlockWidth = 4;    // 块宽. SSE寄存器能一次处理4个float.
        size_t cntBlock = cntbuf / nBlockWidth;    // 块数.
        size_t cntRem = cntbuf % nBlockWidth;    // 剩余数量.
        __m128 xfsSum = _mm_setzero_ps();    // 求和变量。[SSE] 赋初值0
        __m128 xfsLoad;    // 加载.
        const float* p = pbuf;    // SSE批量处理时所用的指针.
        const float* q;    // 将SSE变量上的多个数值合并时所用指针.

        // SSE批量处理.
        for(i=0; i
        {
            xfsLoad = _mm_load_ps(p);    // [SSE] 加载
            xfsSum = _mm_add_ps(xfsSum, xfsLoad);    // [SSE] 单精浮点紧缩加法
            p += nBlockWidth;
        }
        // 合并.
        q = (const float*)&xfsSum;
        s = q[0] + q[1] + q[2] + q[3];

        // 处理剩下的.
        for(i=0; i
        {
            s += p[i];

    展开全文
  • 所以我们可以使用nlargest()函数,nlargest()的优点就是能一次看到最大的几行,而且需要排序。缺点就是只能看到最大的,看到最小的。 我们来看看单价排在前十的数据: 单价排在前十的数据 nlargest()的第一...

    在pandas库里面,我们常常关心的是最大的前几个,比如销售最好的几个产品,几个店,等。之前讲到的head(), 能够看到看到DF里面的前几行,如果需要看到最大或者最小的几行就需要先进行排序。max()和min()可以看到最大或者最小值,但是只能看到一个值。

    所以我们可以使用nlargest()函数,nlargest()的优点就是能一次看到最大的几行,而且不需要排序。缺点就是只能看到最大的,看不到最小的。

    我们来看看单价排在前十的数据:

    单价排在前十的数据

    nlargest()的第一个参数就是截取的行数。第二个参数就是依据的列名。

    这样就可以筛选出单价最高的前十行,而且是按照单价从最高到最低进行排列的,所以还是按照之前的索引。

    还可以按照total_price来进行排名:

    按照total_price排名

    nlargest还有一个参数,keep='first'或者'last'。当出现重复值的时候,keep='first',会选取在原始DataFrame里排在前面的,keep='last'则去排后面的。

    由于nlagerst()不能去最小的多个值,如果我们一定要使用这个函数进行选取也是可以的.

    先设置一个辅助列:

    先设置一个辅助列

    然后在进行选取:

    以辅助列进行选取

    当然了,也可以通过head()加上排序进行选取的。

    那以前这些操作都可以通过其它函数来进行替代的话,nlargest()有什么必要介绍吗?或者说学不学这个函数有什么关系吗?

    这就是我们今天要重点介绍的,如果说要选择不同location_road下的前五名要怎么操作呢?

    很多人可能第一反应会想到先分组然后进行max()操作,但是这样的操作只能选择最大的一列:

    使用max()

    但是使用max有一个问题,就是选取的是每一列的最大值,而不是选取最大值的那一行,也就是说只能在选取单列的最大值的时候才是准确的。

    这个时候我们就要想到apply和lambda的自定义函数了:

    选取多个指标的TOP(N)

    这样就选出了不同loaction_road的price排在前五的行了。

    nlargest()函数在这种场景下使用是非常方便的,而且结果也已经默认排好顺序了。

    还有一些场景下需要计算分组的前几名,然后在进行求和的,这个我们也可以使用nlargest进行操作:

    分组之后进行求和

    使用这种方法会出现报错提示,这个因为在列和索引都存在loaction_road,有重复,系统有警告,在实际使用时可以先改列名再操作。我们也可以换一种方式直接按照索引进行求和,这样就没有警告了:

    展开全文
  • #初始化DataFrame 得到数据集dataset1 print(dataset1) t_optarr=['letter','number'] sumobj={'label':sum,'label2':sum} ##去重 合并求和 并且保留原列表的函数 def rechong_sum_hwj(odata,optarr,sumobj): ...
  • mysql不重复字段值求和

    千次阅读 2013-02-14 03:00:26
    在使用mysql时,有时需要查询出某个字段不重复的记录,虽然mysql提供有distinct这个关键字来过滤掉多余的重复记录只保留一条,但往往只用它来返回不重复记录的条数,而不是用它来返回不重记录的所有值。其原因是...
  • 聚合函数 聚合函数对一组值进行计算并返回单一的值,通常聚合函数...SUM(求和)函数 SUM函数返回表达式中所有值的和或仅非重复值的和。SUM 只能用于数字列。空值将被忽略。 参数说明: ALL:对所有的值应用此聚合函数...
  • 编写函数对数组中的元素求和

    千次阅读 2018-04-03 11:39:56
    函数可以重复调用次,每次只使用参数a传入数组中的一个元素,函数内部可以累计历次传入的值进行求和,每次执行后均把当前的和通过参数sum写入主函数中的某个变量中。 提示:使用静态变量。 输入格式: 一个...
  • C++ 编写函数对数组中的元素求和

    千次阅读 2018-04-07 17:57:02
    函数可以重复调用次,每次只使用参数a传入数组中的一个元素,函数内部可以累计历次传入的值进行求和,每次执行后均把当前的和通过参数sum写入主函数中的某个变量中。提示:使用静态变量。输入格式:一个最多100个...
  • 关于SQL窗口函数中sum 累计求和的错误细节出错案例:按行累加(rows)和按值累加(range)注意:总结: 出错案例: 近期在学习SQL的窗口函数的时候,用sum对成绩进行累计求和出现错误,具体如下: 从图中可以看出按照...
  • 岁月不居,时节如流。 时光荏苒,岁月如梭。 前面两段充分体现了博...存得了不是目的,目的是处理得了,处理得快,处理过程简单,2010的时候微软便引入了Power Query插件用以提升Excel的数据获取、处理能力,20...
  • 哎,说归说,还是需要继续学习CALCULATE函数,也是蛮无奈的。最近白茶在研究帕累托分析法,本期分享一下帕累托ABC分析法的基础——累计求和。 这里简要的说一下什么叫帕累托分析法:意大利经济学家,帕累托研究发现...
  • java8 新特性 Stream流 分组 排序 过滤 多条件去重 (最小、最大、平均、求和),Stream 是用函数式编程方式在集合类上进行复杂操作的工具,其集成了Java 8中的众多新特性之一的聚合操作,开发者可以更容易地使用...
  • Excel 统计符合条件不重复的个数

    万次阅读 2017-11-09 13:32:09
    iamlaosong文 要求从货运明细中统计各省某日发货点数量,公式如下: ...4、Excel使用distinct关键字时似乎很苛刻,除了上面提到的,对字段做处理后取不重复也不行,比如distinct left(日期,3)就不行。    
  • Oracle函数

    万次阅读 多人点赞 2016-05-16 17:43:09
    概述ORACLE函数系列:Oracle常见函数大全Oracle-分析函数之连续求和sum(…) over(…)Oracle-分析函数之排序值rank()和dense_rank()Oracle-分析函数之排序后顺序号row_number()Oracle-分析函数之取上下行数据lag()和...
  • 如果参数是单元格引用,还可以包含区域联合引用。 无论用户指定的参数是一维的数组还是二维的单元格引用,该函数都将返回一个垂直数组,即一维数组。 =Frequency(B2:B10,{5,10,15}) Countif...
  • 获取不重复的数据 ,指定列subset=['letter',' number ',' label '],不保留重复数据:keep=False no_duplicate = dataset.drop_duplicates(subset=[ ' letter ' , ' number ' , ' label ' ] ,keep= False) ...
  • 本人是在一家零售行业工作,所出的教程,都是我日常工作中遇到的 复杂而大量重复的工作 我用python代替去完成它,都是原创内容,非粘贴复制,如果我的文章能够帮助到大家,希望帮忙点个关注。当然,如果有很错别字...
  • IF_SUMIF_COUNTIF三大条件函数

    千次阅读 2015-03-23 11:53:11
    在Excel的众多函数中,有三大条件函数分别是IF函数、COUNTIF函数、SUMIF函数。 Database构成列表或数据库的... ①COUNTIF函数(计数求和)用来计算区域中满足给定条件的单元格的个数。 =COUNTIF(range,criteria) 返
  • 但是我们发现,这个数据是错误的 于是我想到了用 distinct 但是发现用了 ...于是我写了下面的语句来查看结果,加多了一个count函数查看  SELECT s.oid,p.oid AS poid, SUM( priceCount) AS count_p...
  • mysql 重复数据,求和过滤的处理

    千次阅读 2013-04-12 17:07:39
    第一种按照分组求和就可以了 SELECT ID, SUM(NUM) FROM tab GROUP BY ID 第二种 SELECT tab.ID, t2.NUM FROM tab LEFT JOIN (SELECT ID, SUM(NUM) AS NUM FROM tab GROUP BY ID) t2 ON tab.ID = t2.ID ====...
  • Hive内置函数

    千次阅读 2019-06-25 18:02:17
    数学函数 下面表格中的函数为Hive的内置数学函数,大部分当参数为NULL时返回NULL。 返回类型 函数名 描述 bigint round(double a) 返回a经过四舍五入...
  • Numpy排序方式主要概括为直接排序(对数值直接进行排序)和间接排序(根据一个或个键对数据集排序)两种; 直接排序常用sort函数,间接排序用argsort函数和lexsort函数。sort函数五返回值,如果目标函数是个视图...
  • 起因:因领导层需要将电商平台利润核算自动化,原始数据可以动,所以需要用到公式 (PS:其实所谓自动化不是Python / VBA办公自动化,就是嵌套一堆公式,然后每月更新电商后台基础数据,就可以出来利润结果~) ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 60,585
精华内容 24,234
关键字:

多条件不重复求和函数