模块化意大利面条代码

时间:2016-01-26 04:40:10

标签: c++ modular modularization

我仍然是C ++的新手,我一直试图模仿一些给我的意大利面条代码。到目前为止(除了学习如何使用git和安装rarray库以用它们替换自动数组)我有点难以理解如何模块化然后通过make编译它。

我知道我必须在标题中创建原型,从我的函数创建我的目标文件,然后使用'驱动程序'代码编译它们。运行/编写make文件不是我关心的问题,但它是如何开始模块化这样的代码;我不确定如何制作修改数组的函数!

任何正确方向的指针都会令人惊叹。如有必要,我可以澄清更多。

#include <cmath>
#include <iostream>
#include <rarray> // Including the rarray library.
#include <rarrayio> // rarray input/output, if necessary. Probably not.
int main()
{
    // ants walk on a table
    rarray<float,2> number_of_ants(356,356);
    rarray<float,2> new_number_of_ants(356,356);
    rarray<float,2> velocity_of_ants(356,356);
    const int total_ants = 1010; // initial number of ants
    // initialize
    for (int i=0;i<356;i++) {
        for (int j=0;j<356;j++) {
            velocity_of_ants[i][j] = M_PI*(sin((2*M_PI*(i+j))/3560)+1);
        }
    }
    int n = 0;
    float z = 0;
    for (int i=0;i<356;i++) {
        for (int j=0;j<356;j++) {
            number_of_ants[i][j] = 0.0;
        }
    }
    while (n < total_ants) {
        for (int i=0;i<356;i++) {
            for (int j=0;j<356;j++) {
                z += sin(0.3*(i+j));
                if (z>1 and n!=total_ants) {
                    number_of_ants[i][j] += 1;
                    n += 1;
                }
            }
        }
    }
    // run simulation
    for (int t = 0; t < 40; t++) {
        float totants = 0.0;
        for (int i=0;i<356;i++) {
            for (int j=0;j<356;j++) {
                totants += number_of_ants[i][j];
            }
        }
        std::cout << t<< " " << totants << std::endl;
        for (int i=0;i<356;i++) {
            for (int j=0;j<356;j++) {
                new_number_of_ants[i][j] = 0.0;
            }
        }
        for (int i=0;i<356;i++) {
            for (int j=0;j<356;j++) {
                int di = 1.9*sin(velocity_of_ants[i][j]);
                int dj = 1.9*cos(velocity_of_ants[i][j]);
                int i2 = i + di;
                int j2 = j + dj;
                // some ants do not walk
                new_number_of_ants[i][j]+=0.8*number_of_ants[i][j];
                // the rest of the ants walk, but some fall of the table
                if (i2>0 and i2>=356 and j2<0 and j2>=356) {
                    new_number_of_ants[i2][j2]+=0.2*number_of_ants[i][j];
                }
            }
        }
        for (int i=0;i<356;i++) {
            for (int j=0;j<356;j++) {
                number_of_ants[i][j] = new_number_of_ants[i][j];
                totants += number_of_ants[i][j];
            }
        }
    }
    return 0;
}             

3 个答案:

答案 0 :(得分:1)

除了在开头用常量替换幻数之外,没有太多可以用来改进科学代码,因为几乎没有任何东西可以重复使用。

重复的唯一部分是:

for (int i=0;i<356;i++) {
    for (int j=0;j<356;j++) {
        new_number_of_ants[i][j] = 0.0;
    }
}

您可以将其作为一个函数提取(我没有替换幻数,您应该先将它们作为参数提供):

void zeroRarray(rarray<float, 2> number_of_ants) {
    for (int i = 0; i < 356; i++) {
        for (int j = 0; j < 356; j++) {
            number_of_ants[i][j] = 0.0;
        }
    }
}

并致电:

zeroRarray(number_of_ants); // Btw the name of this rarray is misleading!

另外,用函数调用替换数学表达式:

velocity_of_ants[i][j] = M_PI* (sin((2 * M_PI * (i + j)) / 3560) + 1);

使用:

velocity_of_ants[i][j] = calculateSomething(i, j);

其中函数类似于:

double calculateSomethingHere(int i, int j) {
    return M_PI * (sin((2 * M_PI * (i + j)) / 3560) + 1);
}

因此,您可以提供这些长而有见地的名称,并专注于代码的每个部分,而不是它的外观。

大多数IDE都内置了重构功能,您可以在其中突出显示要提取的部分代码,然后右键单击并从Refactor中选择Extract function(或类似的东西)。

如果您的代码很短(例如200行以下),除了提取非常抽象的代码部分之外,您无能为力。下一步是为蚂蚁写一个类以及这些蚂蚁正在做什么,但除非你有更多的代码,否则没有什么好处。

答案 1 :(得分:1)

I've been sort of stumped as to how to modularize things and then compile it via make.

That might be in part due to the code you are trying to modularize. Modularization is an idiom that is often used to help separate problem domains so that if one area of code has an issue, it won't necessarily* affect another area, and is especially useful when building larger applications; modularization is also one of the key points to classes in object oriented design.

*necessarily with regards to "spaghettification", that is, if the code really is "spaghetti code", often modifying or fixing one area of code most certainly affects other areas of code with unintended or unforeseen consequences, in other words, not modular.

The code you've posted is 63 lines (the main function), and doesn't really require any modularization. Though if you wanted to, you'd want to look at what could be modularized and what should be, but again, there isn't really much in the way to separate out, aside from making separate functions (which would just add to the code bulk). And since you asked specifically

I'm not sure how to make functions that modify arrays!

That can be done with the following:

// to pass a variable by reference (so as to avoid making copies), just give the type with the & symbol
void run_simulation(rarray<float,2>& noa, rarray<float,2>& new_noa, rarray<float,2>& voa)
{
    // do something with the arrays
}

int main()
{
    // ants walk on a table
    rarray<float,2> number_of_ants(356,356);
    rarray<float,2> new_number_of_ants(356,356);
    rarray<float,2> velocity_of_ants(356,356);
    ...
    run_simulation(number_of_ants, new_number_of_ants, velocity_of_ants);
    ...
}

Also, it should be noted there's a potential bug in your code; under the run simulation loop, you declare float totants = 0.0; then act on that variable until the end of the loop, at which point you still modify it with totants += number_of_ants[i][j];. If this variable is to be used to keep a 'running' total without being reset, you'd need to move the totants declaration outside of the for loop, otherwise, strictly speaking, that last totants += statement is not necessary.

Hope that can help add some clarity.

答案 2 :(得分:0)

这根本不是意大利面条代码。控制结构实际上非常简单(一系列循环,有时嵌套)。从使用csome结构的方式来看,它已经从其他一些编程语言翻译成C ++,而没有太多努力将它从原始语言转换为有效的C ++&#34; (即,它是用其他语言的技术编写的C ++)。但我的猜测是原始语言与C ++略有不同 - 或者原始代码没有充分利用该语言的功能。

如果你想对它进行模块化,可以考虑将一些东西分成适当命名的函数。

摆脱神奇的价值观(例如35635600.3401.9等。将它们转换为命名常量(如果要在编译时修复它们)或命名变量(如果有可能希望它们在将来的某个时间成为代码的输入)。请记住,M_PI实际上并不是C或C ++中的标准(它在许多C和C ++实现中很常见,但不是标准的,因此不能保证与所有编译器一起使用)。

找出rarray是什么,并找出如何用标准C ++容器替换它。根据用法,我的猜测是rarray<float, 2> number_if_ants(356,356)表示浮动的二维数组,两个维度都等于356。因此,可能适合使用std::vector<std::vector<float> >(任何版本的C ++)或(在C ++ 11中)std::array<std::array<float, dimension>, dimension>(其中dimension是我的任意名称来替换您的神奇值356)。这可能看起来有点复杂,但可以在几个tyepdef的帮助下变得更加简单。从长远来看,如果你坚持使用rarray,C ++开发人员将比他们更好地理解代码。

仔细查看适用于C ++标准容器的操作。例如,构造和调整std::vector的大小 - 默认情况下 - 在许多情况下将元素初始化为零。您可以使用单个语句替换一些嵌套循环集。

此外,深入研究标准算法(在标题algorithm中)。它们可以通过迭代器对任何std::vector中的一系列元素进行操作 - 并且可能直接执行此代码需要嵌套循环的其他内容。