wayne 发表于 2018-1-5 11:07:27

一发不可收拾,我用下面的代码能够说明时间统计的稳定性以及误差的传递,大家可以看看
#include <iostream>
#include <chrono>

void hello()
{
    for( int i = 0,j=0; i < 1e8; ++i ) j++;
}

int main()
{
    for(int k=0;k<10;++k){
      auto t1 = std::chrono::high_resolution_clock::now();
      hello();
      auto t2 = std::chrono::high_resolution_clock::now();

      auto duration = std::chrono::duration_cast<std::chrono::microseconds>( t2 - t1 ).count();

      std::cout << duration/1000. <<"ms"<< std::endl;

    }
    return 0;
}


运行结果是
222.795ms
223.371ms
218.557ms
221.014ms
217.021ms
221.605ms
221.48ms
219.964ms
221.761ms
220.376ms
可见,波动范围是2ms, 统计时间的最后一个不可靠度的位置是1ms, 加大被测试的函数里的循环次数1e8变成10e9, 误差发生了传递,或者说被放大了,最后一个不可靠的位置是10ms,所以,真正严谨的benchmarking还得统计一下耗时的稳定性,即你的统计数据的有效位是哪一位.

2236.23ms
2242.03ms
2209.1ms
2220.01ms
2210.53ms
2212.43ms
2205.2ms
2214.93ms
2221.3ms
2239.92ms

liangbch 发表于 2018-1-5 18:11:17

对于CPU,虽然我们可以从文档中得到每条指令的时钟周期(如http://www.agner.org/optimize/instruction_tables.pdf),但是,你如果做性能测试时会发现,这些数据最多只有一点儿参考价值而已,总的运行时间和指令的时钟周期的累加值差别很大。你永远无法计算出实际运算时间。甚至每次的运行时间都不一样。这不仅和线程切换,中断等外部因素有关,还包括大量的未知因素。过去,我的性能测试总是测试多次(如5次或者7次),然后取最快的那个结果(纵然这样,结果依然是不稳定的,波动范围在10%以内,已经是非常好的了)。但是,为了公平起见(如Maple多次测试的时间差别极大),我改为多次测试的均值。

你如果运行一下GMP源码build出来的那个speed 程序,你会发现,每次得到的结果都不一样。在通常情况下,最大值,最小值在平均值+-%5上下波动。如“speed -C -E -s 1000mpn_mul_basecase”

liangbch 发表于 2018-1-5 18:22:10

mathe 发表于 2018-1-5 09:26
能够直接在C里面调用mathematica的内部接口,或者将你自己的算法编写成能够让mathematica调用的接口,然后 ...

不错的想法,需要研究下mathematica的外部接口怎么做。

wayne 发表于 2018-1-5 22:12:16

liangbch 发表于 2018-1-5 18:11
对于CPU,虽然我们可以从文档中得到每条指令的时钟周期(如http://www.agner.org/optimize/instruction_tab ...

nope, 个人认为这是很要命的。如果不事先声明数据的有效程度[方差,稳定性],我完全可以很安全的说 这些数据是没有什么实际的参考意义的。虽然从感情上,我相信你的人品,相信你有实力在某些算法细节上胜过Mathematica.

确实,网上很多各种benchmarking根本就没给出对应的测试数据的统计方差,我平时也不太当回事。不知怎么的,我竟然在这里较真起来了。莫非只有我一个人是这么对待数据的真实性吗?
=======================================================================

数据的方差大也不要紧,但就是不能没有。 方差大了,咱们还可以另外解释,我们可以说平均性能怎么样,最好性能怎么样,最坏性能怎么样。 是吧

wayne 发表于 2018-1-6 00:26:51

仿照例子,安装目录下【/usr/local/Wolfram/Mathematica/11.2/SystemFiles/Links/WSTP/DeveloperKit/Linux-x86-64】,写了一个测试C/C++测试程序。基本跑通需求。
存在的问题就是到底怎么设置时间的check point才算合理,不是特别的清楚。我先把代码贴出来,有兴趣的自己可以试试。暂时不打算继续较真下去了,到此为止。(反正Mathematica是输了还是赢了,跟我没任何关系, ^_^)

编译的命令如下:
g++ main.cxx -I. -L. -lWSTP64i4 -lm -lpthread -lrt -ldl -luuid -std=c++11
LD_LIBRARY_PATH=. ./a.out -linkname "math -wstp"



#include <iostream>
#include <chrono>
#include <cmath>
#include "wstp.h"

static WSENV ep = (WSENV)0;
static WSLINK lp = (WSLINK)0;

static void error( WSLINK lp)
{
    if( WSError( lp)){
      fprintf( stderr, "Error detected by WSTP: %s.\n",
               WSErrorMessage(lp));
    }else{
      fprintf( stderr, "Error detected by this program.\n");
    }
    exit(3);
}


static void deinit( void)
{
    if( ep) WSDeinitialize( ep);
}


static void closelink( void)
{
    if( lp) WSClose( lp);
}

static void init_and_openlink( int argc, char* argv[])
{
    int err;

    ep =WSInitialize( (WSParametersPointer)0);
    if( ep == (WSENV)0) exit(1);
    atexit( deinit);

    lp = WSOpenArgv( ep, argv, argv + argc, &err);
    if(lp == (WSLINK)0) exit(2);
    atexit( closelink);
}


static void read_and_print_expression( WSLINK lp)
{
    const char *s;
    int n;
    int i, len;
    double r;
    static int indent;

    switch( WSGetNext( lp)) {
    case WSTKSYM:
      std::cout<< __LINE__ <<std::endl;
      WSGetSymbol( lp, &s);
      printf( "%s ", s);
      WSReleaseSymbol( lp, s);
      break;
    case WSTKSTR:
      std::cout<< __LINE__ <<std::endl;
      WSGetString( lp, &s);
      printf( "\"%s\" ", s);
      WSReleaseString( lp, s);
      break;
    case WSTKINT:
      std::cout<< __LINE__ <<std::endl;
      WSGetInteger( lp, &n);
      printf( "%d ", n);
      break;
    case WSTKREAL:
//      std::cout<< __LINE__ <<std::endl;
      WSGetReal( lp, &r);
      printf( "%g ", r);
      break;
    case WSTKFUNC:
      std::cout<< __LINE__ <<std::endl;
      indent += 3;
      printf( "\n %*.*s", indent, indent, "");
      if( WSGetArgCount( lp, &len) == 0){
            error( lp);
      }else{
            read_and_print_expression( lp);
            printf( "[");
            for( i = 1; i <= len; ++i){
                read_and_print_expression( lp);
                if( i != len) printf( ", ");
            }
            printf( "]");
      }
      indent -= 3;
      break;
    case WSTKERROR:
      std::cout<< __LINE__ <<std::endl;
    default:
      error( lp);
    }
}


int main(int argc, char* argv[])
{
    init_and_openlink( argc, argv);

    int pkt,x,n;
    std::cout<< "put x: "<<std::endl;
    std::cin>>x;
    std::cout<< "put n: "<<std::endl;
    std::cin>>n;
    std::string cmd = "N,"+std::to_string(n)+"]";
    std::cout<< "Expression: "<<cmd<<std::endl;

//    WSPutFunction( lp, "N", 2);
//    WSPutFunction( lp, "Log", 1);
//    WSPutInteger( lp, x);
//    WSPutInteger( lp, n);
//    WSEndPacket( lp);

    WSPutFunction(lp, "ToExpression", 1);
    WSPutString(lp, cmd.c_str());
    WSEndPacket(lp);

    while( (pkt = WSNextPacket(lp), pkt) && pkt != RETURNPKT) {
      WSNewPacket( lp);
      if (WSError( lp)) error( lp);
    }

    auto t1 = std::chrono::high_resolution_clock::now();
    read_and_print_expression( lp);
    auto t2 = std::chrono::high_resolution_clock::now();
    std::cout<< "cost:"<<std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1).count()/1000.<<"ms"<<std::endl;

    WSPutFunction( lp, "Exit", 0L);

    return 0;

}

zeroieme 发表于 2018-3-17 23:47:15

不知论文进度怎样了

liangbch 发表于 2018-3-20 09:55:53

这个事情暂时放下,也没有重启的时间表

无心人 发表于 2018-4-8 17:37:44

我提供个测试例子吧,统一使用一个很大的常数,比如10000内的质数乘到一起,结果减1,再平移小数点变成整数部分小于10的小数,预先存储成文件,然后读进程序来运算,然后再测试求时间,测试时候从读完这个小数后计时,这样就既能求的比最小测量误差大很多的时间了,又避免了可能的预先储存结果的问题

nyy 发表于 2022-11-15 14:17:40

我就好奇,干啥工作需要把对数算上万位?

liangbch 发表于 2022-12-13 11:14:56

nyy 发表于 2022-11-15 14:17
我就好奇,干啥工作需要把对数算上万位?

对技术的追求是无止尽的. 圆周率已经计算到几万亿位了,但就应用而言,几十位圆周率也足够了,不是吗?
页: 1 2 3 4 5 [6] 7
查看完整版本: 重大消息-一种新的任意精度对数算法研制成功