yxyxyx1700 发表于 2012-2-8 20:06:51

求高效的基础运算库~~~

本人新手,请问VC++下有没有比math.h库更加高效的基础运算库,或者对pow、log、sin、cos、sqrt等函数的优化方法~~(只考虑一般情况即可,不需要考虑大数及高精度),请各位高手赐教!!!万分感谢!!!

liangbch 发表于 2012-2-9 13:46:16

这些数学函数的实现是通过CPU/FPU指令实现的,已经非常快了,应该能够满足绝大多数需要,而楼主似乎对其性能不满意却又提到不考虑高精度和大数,这就让人搞不懂了。个人认为就double精度而言,这些函数很难有实质的改进了,任何算法的实现都应该快不过CPU指令。

sielw 发表于 2012-2-13 09:53:32

弱弱问一句,哪里能看到math.c?

liangbch 发表于 2012-2-13 13:35:19

2# liangbch
刚才写了一个程序,对VC6中的数学函数的性能进行了测试。结果如下,我的CPU是Intel E8500, CPU频率是3.16GH
sqrt() 花费时间约4.3 CPU 周期
sin() 花费时间约13 CPU周期
log() 花费时间约10 CPU周期

liangbch 发表于 2012-2-13 13:38:33

这里贴出所有的代码,注意,需要修改 CPU_FREQ的定义,使得它的值和你的CPU一致。
编译环境为VC6.0
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <windows.h>

#definePI 3.1415926535897932384626433832795
#defineDATA_COUNT 1000
#defineCPU_FREQ(3.16e9)//CPU frequency, need always change this definition for match your CPU

typedef double ( *lpfn_math )(double);

unsigned __int64 s_u64Frequency = 1;
unsigned __int64 s_u64Start, s_u64End;

double data;
double result;

void testFun( const lpfn_math pFun,
                       const char* lpszFunName,
                       const inttestTimes )
{

        int i,j;
        double t;
        double ns;

        QueryPerformanceFrequency((LARGE_INTEGER *)&s_u64Frequency );

        printf( "\nTest function: %s() %u times\n",
                lpszFunName, testTimes*DATA_COUNT );

        QueryPerformanceCounter((LARGE_INTEGER *)&s_u64Start );
        for (i=0;i<testTimes;i++)
        {
                for (j=0;j<DATA_COUNT;j++)
                {
                        result=pFun(data);
                }
        }
        QueryPerformanceCounter((LARGE_INTEGER *)&s_u64End );

        t = (double)(( s_u64End - s_u64Start ) / (double) s_u64Frequency );
        printf( "Elapsed time: %d ms\n", (int)(t*1000));

        ns=(t * 1e9) /(double)(DATA_COUNT *testTimes); //calc the time of one sqrt function call in nanosecond
        printf("%s() spend %f ns\n", lpszFunName,ns );
        printf("%s() spend %f cpu cycle\n", lpszFunName, (ns*1e9)/CPU_FREQ);
}

void test_sqrt()
{
        int c,n1,n2;
        c=0;
        while (c<DATA_COUNT)
        {
                n1=rand();
                n2=rand();
                if (n1!=0 && n2!=0)
                {
                        data=double(n1) / double(n2);
                        c++;
                }
        }
        testFun( sqrt,"sqrt",1000);
}

void test_sine()
{
        int c,n;
        c=0;
        while (c<DATA_COUNT)
        {
                n=(rand() % 1000)+1;
                data=double(n) / 1000.00 * PI * 0.5;//data is i/1000*PI/2, i=1..1000
                c++;
        }
        testFun(sin,"sin",1000);
}

void test_log()
{
        int c,n1,n2;
        c=0;
        while (c<DATA_COUNT)
        {
                n1=(rand() % 1000)+1;
                n2=rand() % 1000;
                data=double(n1) + double(n2) * 0.001;//data[ i ] always between 1.000 to 1000.999
                c++;
        }
        testFun( log,"log",1000);
}

int main(int argc, char* argv[])
{
        test_sqrt();
        test_sine();
        test_log();
        return 0;
}

gxqcn 发表于 2012-2-13 14:19:36

2# liangbch
刚才写了一个程序,对VC6中的数学函数的性能进行了测试。结果如下,我的CPU是Intel E8500, CPU频率是3.16GH
sqrt() 花费时间约4.3 CPU 周期
sin() 花费时间约13 CPU周期
log() 花费时间约10 CPU周 ...
liangbch 发表于 2012-2-13 13:35 http://bbs.emath.ac.cn/images/common/back.gif

感觉比我想象的快多了,我原本以为它们都得耗上百余个指令周期呢。

liangbch 发表于 2012-2-13 14:32:55

很不幸,VC6中没有数学函数的源代码,即使在安装了VC是选择 VC++ Runtime Libraries ->CRT Source Code 也是如此。我能够在调试时进入其他库函数的源文件,如memset,但是不能进入数学函数所在的源文件。搜索CRT源码目录,仅仅找到2个导入库的定义文件,见下。
C:\Program Files\Microsoft Visual Studio\VC98\CRT\SRC\Intel\_SAMPLD_.DEF
C:\Program Files\Microsoft Visual Studio\VC98\CRT\SRC\Intel\_SAMPLE_.DEF

G-Spider 发表于 2012-2-13 16:43:45

查看了一下,msvcrt.dll和 相关的LIBC.LIB 库,以上函数还是对fsqrt , fsin ,fcos 的封装。
不知是否还有用到其它库函数。_sqrt:

var_4                = word ptr -4
arg_0                = dword        ptr4
arg_4                = dword        ptr8

                lea        edx,
                call        __fload_withFB

loc_77C1D52D:
                push        edx
                fstcw       
                mov        eax,
                jz        short loc_77C1D589
                cmp        , 27Fh
                jz        short loc_77C1D545
                call        __load_CW

loc_77C1D545:
                test        eax, 80000000h
                jnz        short loc_77C1D56B
                fsqrt
      
      ....

;=======================================


__fload_withFB:

var_A                = tbyte        ptr -0Ah

                mov        eax,
                and        eax, 7FF00000h
                cmp        eax, 7FF00000h
                jz        short loc_77C20C37
                fld        qword ptr
                retn
; --------------------------------

loc_77C20C37:
                mov        eax,
                sub        esp, 0Ah
                or        eax, 7FFF0000h
                mov        dword ptr , eax
                mov        eax,
                mov        ecx,
                shld        eax, ecx, 0Bh
                shl        ecx, 0Bh
                mov        , eax
                mov        dword ptr , ecx
                fld       
                add        esp, 0Ah
                test        eax, 0
                mov        eax,
                retn
__fload_withFB        endp

liangbch 发表于 2012-2-13 22:33:41

关于求浮点数(单精度和双精度)的平方根,下面的文章值得一看,它利用IEEE754浮点数的格式,直接求出一个比较好的初值,然后使用牛顿迭代求精。
http://ilab.usc.edu/wiki/index.php/Fast_Square_Root

wayne 发表于 2012-2-15 11:37:45

在 Android 源码目录的 bionic/libm/src路径下找到 平方根的实现e_sqrt.c:
感兴趣的可以看看:

页: [1] 2
查看完整版本: 求高效的基础运算库~~~