Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 本征:用本征本质简化表达式_C++_Eigen - Fatal编程技术网

C++ 本征:用本征本质简化表达式

C++ 本征:用本征本质简化表达式,c++,eigen,C++,Eigen,我试图用向量中的对应值缩放矩阵中的所有列。当该值为0时,我想用一列替换该列,该列来自按常量缩放的其他矩阵。听起来很复杂,但在Matlab中非常简单(但可能没有完全优化): 在C++中用也很简单: RowVectorXf b; Matrix3Xf a, c; float x; for (int i = 0; i < b.size(); i++) { if (b(i) != 0) { a.col(i) = a.col(i) / b(i); } else {

我试图用向量中的对应值缩放矩阵中的所有列。当该值为0时,我想用一列替换该列,该列来自按常量缩放的其他矩阵。听起来很复杂,但在Matlab中非常简单(但可能没有完全优化):

在C++中用<<代码> for循环 >也很简单:

RowVectorXf b;
Matrix3Xf a, c;
float x;
for (int i = 0; i < b.size(); i++) {
    if (b(i) != 0) {
        a.col(i) = a.col(i) / b(i);
    } else {
        a.col(i) = c.col(i) * x;
    }
}
但编译时不会出现错误
error:operans to?:具有不同的类型…(类型的长列表)

编辑: 我添加了测试答案的代码,如下所示:

#include <Eigen/Dense>
#include <stdlib.h>
#include <chrono>
#include <iostream>

using namespace std;
using namespace Eigen;

void flushCache()
{
    const int size = 20 * 1024 * 1024; // Allocate 20M. Set much larger than L2
    volatile char *c = (char *) malloc(size);
    volatile int i = 8;
    for (volatile int j = 0; j < size; j++)
        c[j] = i * j;

    free((void*) c);
}

int main()
{
    Matrix3Xf a(3, 1000000);
    RowVectorXf b(1000000);
    Matrix3Xf c(3, 1000000);
    float x = 0.4;

    a.setRandom();
    b.setRandom();
    c.setRandom();

    for (int testNumber = 0; testNumber < 4; testNumber++) {
        flushCache();
        chrono::high_resolution_clock::time_point t1 = chrono::high_resolution_clock::now();
        for (int repetition = 0; repetition < 1000; repetition++) {
            switch (testNumber) {
                case 0:
                    for (int i = 0; i < b.size(); i++) {
                        if (b(i) != 0) {
                            a.col(i) = a.col(i) / b(i);
                        } else {
                            a.col(i) = c.col(i) * x;
                        }
                    }
                    break;
                case 1:
                    for (int i = 0; i < b.size(); i++) {
                        a.col(i) = (b(i) != 0) ? (a.col(i) / b(i)).eval() : (c.col(i) * x).eval();
                    }
                    break;
                case 2:
                    for (int i = 0; i < b.size(); i++) {
                        a.col(i) = (b(i) != 0) ? (a.col(i) * (1.0f / b(i))) : (c.col(i) * x);
                    }
                    break;
                case 3:
                    a = b.cwiseEqual(0.0f).replicate< 3, 1 >().select(c * x, a.cwiseQuotient(b.replicate< 3, 1 >()));
                    break;
                default:
                    break;
            }
        }

        chrono::high_resolution_clock::time_point t2 = chrono::high_resolution_clock::now();
        auto duration = chrono::duration_cast< chrono::milliseconds >(t2 - t1).count();
        cout << "duration: " << duration << "ms" << endl;
    }

    return 0;
}
顺便说一下,不使用setRandom初始化变量,输出完全不同:

duration: 10255ms
duration: 11076ms
duration: 8250ms
duration: 5198ms
@chtz认为这是因为非规范化的值,但我认为这是因为分支预测。这是因为分支预测的一个证据是,初始化
b.setZero()导致与不初始化相同的计时

a.col(i) = (b(i) != 0) ? (a.col(i) * (1.0f/b(i))) : (c.col(i) * x);
将起作用,但这只是因为表达式的类型相同,并且在任何时候都可能不安全(a
?:
表达式基本上被转换为与
if
-
else
分支相同。)

如果您喜欢将其写入一行,则以下表达式应适用:

a = b.cwiseEqual(0.0f).replicate<3,1>().select(c*x, a.cwiseQuotient(b.replicate<3,1>()));
a=b.cwiseEqual(0.0f).replicate().select(c*x,a.cWisequot(b.replicate());

同样,我怀疑它是否会带来显著的性能差异。

可能您需要类似于
.eval()
.finished()
的东西。否则,您会遇到一些奇怪的表达式模板返回类型。@HenriMenke Yes,在这两个表达式中添加
.eval()
也会使其正常工作(
.finished()
用于逗号初始值设定项)我想对于一个现实的基准测试,你也应该将
b
的一些随机元素设置为0,否则就不太可能得到0。3个元素乘以
1.f/b(i)
当然比3个元素除以
b(i)
要快。对于未初始化变量的结果,我感到非常惊讶(但这只是证明了永远不会盲目相信您关于基准测试的直觉…@chtz是的,对于0,我完全同意。关于除法,我希望它可以优化为倒数乘法。在gcc/clang中,标志
-frecipracal math
应该足以允许这样做。我建议在使用之前先阅读
-ffast math
的所有效果。(这真的取决于你的用例,哪种优化是可以的)我在我的电脑上做了一些测量(在一个特定的情况下)
a.col(I)=(b(I)!=0)?(a.col(i)*(1.0f/b(i)):(c.col(i)*x)
a.col(i)=(b(i)!=0)快10%左右?(a.col(i)/b(i)).eval():(c.col(i)*x.eval()。不幸的是
a=b.cwiseEqual(0.0f).replicate().select(c*x,a.cwisequot(b.replicate())使断言失败
aLhs.rows()==aRhs.rows()&&aLhs.cols()==aRhs.cols()
。我将在我的问题中添加测试代码。在您的测试中,代码
b
a
c
小10倍。此外,为了进行实际比较,我建议使用
setRandom
初始化矩阵,或者使用实际值更好。未初始化的矩阵将包含不切实际的非规范化和非有限值(几乎在所有平台上都会影响性能)。。。我为那只虫子感到抱歉!还感谢您对setRandom的提示。我没有使用它,因为初始化大型矩阵需要一些时间,但效果是巨大的!前三个测试的执行时间几乎相同,但最后一个测试的执行时间增加了一倍多!我将把它添加到queston中,以防万一有人感兴趣。顺便说一下,我不认为是非规范化的值,而是分支预测,在时间上产生了差异。
duration: 10255ms
duration: 11076ms
duration: 8250ms
duration: 5198ms
a.col(i) = (b(i) != 0) ? (a.col(i) * (1.0f/b(i))) : (c.col(i) * x);
a = b.cwiseEqual(0.0f).replicate<3,1>().select(c*x, a.cwiseQuotient(b.replicate<3,1>()));