首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >生成正交向量的算法: C++实现

生成正交向量的算法: C++实现
EN

Code Review用户
提问于 2019-09-22 10:57:39
回答 1查看 2.1K关注 0票数 6

最近我问了相似问题,但是算法是用Python实现的。现在我尝试实现相同的算法,但是在C++中(我对它非常陌生):

代码语言:javascript
复制
#include<iostream>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include <tgmath.h>
using namespace std;



const int MAXRANGE = 1000;

int randint(int low, int high){
    return rand() % (high - low) + low;

    }

void generate_vector(float vec[],int dimension){
    for (int i = 0; i < dimension; i++){
        vec[i] = randint(-MAXRANGE,MAXRANGE);
        }

    // We need to ensure that the last entry doesn't equal to zero

    if (vec[dimension-1] == 0){
        while (vec[dimension-1] == 0){
            vec[dimension-1] = randint(-MAXRANGE,MAXRANGE);

        }
    }


}

void generate_orthogonal (float *vector, float orthogonal_vector[], int dimension){
    float last_entry;
    float dot_product = 0;
    for (int i = 0; i < dimension -1; i++){
        orthogonal_vector[i] = randint(-MAXRANGE,MAXRANGE);
    }
    for (int i = 0; i < dimension -1; i++){
        dot_product = dot_product + (vector[i] * orthogonal_vector[i]);
    }
    last_entry = -(dot_product/vector[dimension-1]);
    orthogonal_vector[dimension-1] = last_entry;
}


float dot_product(float *vector1, float vector2[],int dimension){
    float sum = 0;
    for (int i = 0; i < dimension; i++){
        sum += (vector1[i])*(vector2[i]);
    }
    return sum;
}


void print_vector(float *A,int dim){
    cout << "(";
    for (int i = 0; i < dim; i++){
        if (i == dim -1){
            cout << A[i];
        }
        else{
            cout << A[i] << ",";}
    }
    cout << ")^T" << endl;
}
int main(){
    srand(time(0));
    int dimension;
    cout << "Choose dimension for the vector: ";
    cin >> dimension;
    float arbitrary_vector[dimension], orthogonal[dimension];
    generate_vector(arbitrary_vector,dimension);
    generate_orthogonal(arbitrary_vector,orthogonal,dimension);
    cout << "First vector: ";
    print_vector(arbitrary_vector,dimension);
    cout << "Orthogonal vector: ";
    print_vector(orthogonal,dimension);
    cout << "Dot product of the vectors: ";
    cout << dot_product(arbitrary_vector,orthogonal,dimension) << endl;

}

还有什么可以改进的?

正如一些人之前指出的,如果第一个向量的最后一个条目是0,则该算法会抛出异常。我做了一个小小的修改,以确保generate_vector函数不会生成最后一个元素为零的向量。

EN

回答 1

Code Review用户

发布于 2019-09-22 11:58:52

欢迎来到C++。

不过,您似乎或多或少地试图编写C代码,而不是C++。让我们看看您可以改进什么:

  1. 永远不要做using namespace std;,这是一个可怕的做法,使你陷入麻烦真的很快。std::并不难打字,所以尽早养成这个习惯。
  2. 如果您有编译时间常量,则通过constexpr使用它们
  3. 您的dot_product函数已在标准库中实现。它被称为inner_product。因此,下面的代码可以用下面的代码( (vector1我)*(vector2我);(a.cbegin(),a.cend(),b.cbegin(),float (0.0))替换为vector2[],int维数= 0;for (int i= 0;i<维度;i++){ sum += }返回和;}。
  4. 类似地,还有一个用生成器填充向量的generate函数。请注意,C++在<random>头中有各种好的随机数生成器(rand()不是其中之一)。我不知道为什么要用整数来表示浮点向量,但是你可以很容易地适应。编辑:由@L.F.发现的合并问题。#包括 #包括类randomStreamUniformInt { public:显式randomStreamUniformInt(int lower_bound,int upper_bound):mt(std::random_device {} ()),uniform_dist(lower_bound,upper_bound) {显randomStreamUniformInt(int lower_bound,int upper_bound,double种子):mt(种子),uniform_dist(lower_bound,upper_bound) {} int运算符() (){返回uniform_dist(mt);std::mt19937_64 mt;std::uniform_int_distribution<> uniform_dist;};静态randomStreamUniformInt rng(-MAXRANGE,MAXRANGE);std::vector生成随机(const std::size_t numElements) { std::vector res(numElements);std: generate (res.begin(),res.end(),rng);返回res;}将随机数生成器作为参数而不是全局变量传递会更好。我把它作为一个练习。
  5. 应该对数组(如std::vectorstd::array )使用标准工具,具体取决于编译时是否知道大小。因此,下面的代码: float arbitrary_vector尺寸,正交尺寸应该以std::vector arbitrary_vector =generate_random(维度)的形式写得更好;注意,将每个声明放在一行中总是更好。
  6. 您的方法generate_orthogonal可以得到相应的改进。std::vector generate_orthogonal(const std::vector& a) { //获取一些随机数据std::vector b= generate_random(a.size());//查找a //中最后一个非零项,我们必须通过std将反向迭代器转换为迭代器::prev(rit.base()) auto = const浮子f -> bool {返回f == float(0.0);};auto end = std::prev(std::find_if_not(a.crbegin(),a.crend(),IsZero).base();//确定到结束浮点数dot_product =std::inner_product的点积(a.cbegin(),end,b.cbegin(),float(0.0));//设置b的值,使内积bA.cbegin(),结束) =- dot_product / (* end );返回b};

所以把它放在一起,看起来会是这样的:

代码语言:javascript
复制
#include <algorithm>
#include <random>
#include <vector>

constexpr int MAXRANGE = 1000;

class randomStreamUniformInt {
public:
    explicit randomStreamUniformInt(int lower_bound, int upper_bound)
    : mt(std::random_device{}()), uniform_dist(lower_bound, upper_bound) {}
    explicit randomStreamUniformInt(int lower_bound, int upper_bound, double seed)
    : mt(seed), uniform_dist(lower_bound, upper_bound) {}

    int operator() () { return uniform_dist(mt); }
private:
    std::mt19937_64                     mt;
    std::uniform_int_distribution<>     uniform_dist;
};

static randomStreamUniformInt rng(-MAXRANGE, MAXRANGE); 

std::vector<float> generate random(const std::size_t numElements) {
    std::vector<float> res(numElements);
    std::generate(res.begin(), res.end(), rng);
    return res;
}

std::vector<float> generate_orthogonal(const std::vector<float>& a) {
    // get some random data
    std::vector<float> b = generate_random(a.size());

    // find the last non zero entry in a
    // We have to turn the reverse iterator into an iterator via std::prev(rit.base())
    auto IsZero = [] (const float f) -> bool { return f == float(0.0);};
    auto end = std::prev(std::find_if_not(a.crbegin(), a.crend(), IsZero).base());

    // determine the dot product up to end
    float dot_product = std::inner_product(a.cbegin(), end, b.cbegin(), float(0.0));

    // set the value of b so that the inner product is zero
    b[std::distance(a.cbegin(), end)] = - dot_product / (*end);

    return b;
}

int main() {
    std::size_t dimension = 20;

    std::vector<float> a = generate_random(dimension);
    std::vector<float> b = generate_orthogonal(a);
}
票数 9
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/229457

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档