C++ C+中的快速百分位数+;-速度比精度更重要

C++ C+中的快速百分位数+;-速度比精度更重要,c++,performance,C++,Performance,这是一项后续行动 我有一个365个每日现金流的排序数组(xDailyCashflowsDistro),我随机对其进行365次采样,以获得生成的年度现金流。生成是由 1/ picking a random probability in the [0,1] interval 2/ converting this probability to an index in the [0,364] interval 3/ determining what daily cashflow corresponds

这是一项后续行动

我有一个365个每日现金流的排序数组(
xDailyCashflowsDistro
),我随机对其进行365次采样,以获得生成的年度现金流。生成是由

1/ picking a random probability in the [0,1] interval
2/ converting this probability to an index in the [0,364] interval
3/ determining what daily cashflow corresponds to this probability by using the index and some linear aproximation.
将365个每日产生的现金流相加。按照前面提到的思路,我的代码预先计算排序的每日现金流的差异(
xDailycashFlowDiff
),其中

因此,整个代码看起来像

double _dIdxConverter = ((double)(365 - 1)) / (double)(RAND_MAX - 1);

for (  unsigned int xIdx = 0; xIdx < _xCount; xIdx++ )
{
    double generatedVal = 0.0;
    for (  unsigned int xDayIdx = 0; xDayIdx < 365; xDayIdx ++ )
    {
         double dIdx    = (double)fastRand()* _dIdxConverter;       
         long   iIdx1   = (unsigned long)dIdx;                          
         double dFloor  = (double)iIdx1;                                

        generatedVal += xDailyCashflowsDistro[iIdx1] + xDailyCashflowDiffs[iIdx1] *(dIdx  - dFloor);
    }
    results.push_back(generatedVal) ;
}
double-dIdxConverter=((double)(365-1))/(double)(RAND_MAX-1);
for(无符号整数xIdx=0;xIdx<\uxcount;xIdx++)
{
双生成值=0.0;
对于(无符号整数xDayIdx=0;xDayIdx<365;xDayIdx++)
{
double-dIdx=(double)fastRand()*\u-dIdxConverter;
长iIdx1=(无符号长)dIdx;
双D地板=(双)iIdx1;
generatedVal+=xDailyCashflowsDistro[iIdx1]+xDailyCashFlowDiff[iIdx1]*(dIdx-dFloor);
}
结果:推回(生成VAL);
}
\u xCount
(模拟的数量)是1K+,通常是10K

问题: 目前正在进行15分钟的模拟(与写入第一个线程时的100 K相比),在3.4GHz的机器上大约需要10分钟。由于问题的性质,这15米不太可能在未来大幅降低,只会增加。使用VTune分析器后,我被告知最后一行(
generatedVal+=…
)生成80%的运行时间。我的问题是,为什么以及如何处理这个问题

我尝试过的事情:

1/去掉
(dIdx-dFloor)
部分,看看双差和乘法是否是罪魁祸首-运行时间下降了两个百分点

2/将
xDailyCashflowsDistro
xDailyCashFlowDiff
声明为
\u restict
,以防止编译器认为它们相互依赖-无更改

3/尝试使用16天(而不是365天)来查看是否是缓存未命中拖累了我的性能-不是一个微小的变化

4/尝试使用浮动而不是双精度-无变化

5/使用不同的/fp编译:-无更改

6/编译为x64-对双ulong转换有影响,但所讨论的行不受影响

我愿意牺牲的是分辨率-如果速度增益很大,我不在乎最后生成的VAL是100010.1还是100020.0

编辑:
每日/年度现金流与整个投资组合相关。我可以将所有每日现金流除以portflio规模,从而(在99.99%的置信水平下)确保每日现金流/pflio_规模不会超出[-1000,+1000]区间。不过,在这种情况下,我需要百分之一百的精度。

也许您可以将分段线性函数转换为其值的分段线性“直方图”。您正在采样的数字似乎是该直方图中365个样本的总和。你所做的不是一种特别快速的方法,从该直方图的365个样本的总和中进行采样


您可以尝试计算傅里叶(或小波或类似)变换,只保留前几个项,将其提高到第365次方,然后计算逆变换。你最终不会得到概率分布,但在0以下或1以上不应该有“太多”质量,总质量也不应该与使用此技术的1“太不同”。(我不知道你的数据是什么样的;由于数学上的原因,这项技术很可能行不通。)

你在处理现金交易,而你对精确性不感兴趣?这到底是怎么回事?啊。。。开玩笑的浮点运算反正对钱没好处…@user2485710:我编辑之前你就写过+-10 CZK除以较大的pflio尺寸为零差。如果
速度比精度更重要,则
结果=42应该这样做,速度相当快。无论如何,我会将
xDailyCashflowsDistro[iIdx1]
和另一个值存储在一个标量变量中,以避免查找……我认为您可以将此算法视为包含两个具有不同统计信息的部分。主要部分是对一天的总数进行汇总,这一部分为您的分析添加了实质内容,并且在很大程度上取决于您的实际百分比分布。插值部分对随机值求和,其范围仅略微取决于百分位分布。最后一部分可能有一个干净的高斯分布(你可以测试一下)。如果确实是这种情况,您可以用取自此高斯分布的值替换365次插值。续:对于合理平坦的分布,此高斯分布的平均值可能约为
(distro[364]-distro[0])/365/2
(即平均步长的一半),且标准偏差较小,因为你对365个均匀分布的数字求和。根据这个分析的结果,你可以考虑忽略插值部分,现在你可以量化它对最终结果的实际影响。另外,我不是统计学家,如果这不合理,不要怪我!
double _dIdxConverter = ((double)(365 - 1)) / (double)(RAND_MAX - 1);

for (  unsigned int xIdx = 0; xIdx < _xCount; xIdx++ )
{
    double generatedVal = 0.0;
    for (  unsigned int xDayIdx = 0; xDayIdx < 365; xDayIdx ++ )
    {
         double dIdx    = (double)fastRand()* _dIdxConverter;       
         long   iIdx1   = (unsigned long)dIdx;                          
         double dFloor  = (double)iIdx1;                                

        generatedVal += xDailyCashflowsDistro[iIdx1] + xDailyCashflowDiffs[iIdx1] *(dIdx  - dFloor);
    }
    results.push_back(generatedVal) ;
}