性能问题:Java与C ++


69

我一直都听说C ++比Java更高效(这就是为什么大多数游戏都是用C ++开发的原因)。

我写了一个小的算法,使用完全相同的算法来解决Java和C ++中的“八皇后难题”,然后开始增加数字或平方。当到达20 * 20甚至22 * 22的棋盘时,似乎Java更为有效(3秒对C ++为66秒)。

我不知道为什么,但是我是从C ++开始的,所以我很可能会犯一些巨大的性能错误,所以我很乐意接受任何可以帮助我了解发生了什么的信息。

以下是我在Java中使用的代码:

import java.awt.Point;
import java.util.ArrayList;
import java.util.List;

public class HuitDames {

    /**
     * La liste des coordnnées des dames.
     */
    private static List<Point> positions = new ArrayList<>();

    /**
     * Largeur de la grille.
     */
    private static final int LARGEUR_GRILLE = 22;


    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        int i = 1;
        placerDame(i);
        for (Point point : positions) {
            System.out.println("(" + point.x + "; " + point.y + ")");
        }
    }

    /**
     * Place une dame et return true si la position est bonne.
     * @param i le numéro de la dame.
     * @return si la position est bonne.
     */
    private static boolean placerDame(int i) {

        boolean bonnePosition = false;
        for (int j = 1; j <= LARGEUR_GRILLE && bonnePosition == false; j++) {
            Point emplacement = new Point(i, j);
            positions.add(emplacement);
            if (verifierPrise(emplacement) && (i == LARGEUR_GRILLE || placerDame(i + 1))) {
                bonnePosition = true;
            }
            else {
                positions.remove(i - 1);
            }
        }

        return bonnePosition;
    }

    /**
     * Vérifie que la nouvelle position n'est pas en prise avec une position déjà présente.
     * @param position la position de la nouvelle dame.
     * @return Si la position convient par rapport aux positions des autres dames.
     */
    private static boolean verifierPrise(Point position) {
        boolean nonPrise = true;
        for (Point point : positions) {
            if (!point.equals(position)) {
                // Cas où sur la même colonne.
                if (position.y == point.y) {
                    nonPrise = false;
                }
                // Cas où sur même diagonale.
                if (Math.abs(position.y - point.y) == Math.abs(position.x - point.x)) {
                    nonPrise = false;
                }
            }
        }

        return nonPrise;
    }
}

下面是C ++中的代码:

#include <iostream>
#include <list>
#include <math.h>
#include <stdlib.h>

using namespace std;


// Class to represent points.
class Point {

    private:
        double xval, yval;

    public:
        // Constructor uses default arguments to allow calling with zero, one,
        // or two values.
        Point(double x = 0.0, double y = 0.0) {
                xval = x;
                yval = y;
        }

        // Extractors.
        double x() { return xval; }
        double y() { return yval; }
};

#define LARGEUR_GRILLE 22
list<Point> positions;


bool verifierNonPrise(Point emplacement) {
    bool nonPrise = true;
    for (list<Point>::iterator it = positions.begin(); it!= positions.end(); it++) {
        if (it->x() != emplacement.x()) {
            if (it->y() == emplacement.y()) {
                nonPrise = false;
            }
            if (abs(it->y() - emplacement.y()) == abs(it->x() - emplacement.x())) {
                nonPrise = false;
            }
        }
    }

    return nonPrise;
}

bool placerDame(int i) {
    bool bonnePosition = false;
    for (int j = 1; j <= LARGEUR_GRILLE && !bonnePosition; j++) {
        Point emplacement(i,j);
        positions.push_back(emplacement);
        if (verifierNonPrise(emplacement) && (i == LARGEUR_GRILLE || placerDame(i + 1))) {
            bonnePosition = true;
        }
        else {
            positions.pop_back();
        }
    }

    return bonnePosition;
}

int main()
{
    int i = 1;
    placerDame(i);
    for (list<Point>::iterator it = positions.begin(); it!= positions.end(); it++) {
        cout << "(" << it->x() << "; " << it->y() << ")" << endl;
    }
    return 0;
}

16
您是否在启用优化的情况下编译了C ++代码?对于gcc和clang,请添加-O3到命令行。
Baum mit Augen

22
“我一直听说C ++比Java更高效”,因为通常如此。
本杰明·特伦特

20
Java击败C ++并不少见。与使用任何现成的C ++编译器/链接器相比,可以对JITC优化的Java程序进行更严格的优化。例如,JITC可以轻松地对Point进行内联操作,而C ++通常只能在声明函数可内联的情况下进行内联。
热门点击2014年

8
@HotLicks请注意,声明函数为inlinable确实不影响它们是否内联。在此示例中,Point的方法是隐式内联的。但是,它们甚至不是必需的。数据应该是公开的。
juanchopanza 2014年

9
@HotLicks当然可以,但是OP的代码是内联的。性能下降很可能是使用std::list。至于getter,如果内联,它们也将被优化,但是使用它们可能导致生成数据成员的额外副本,因为它们在语义上返回值。无论如何,如果用两种语言正确地编码,那么在如此简单的数字问题上,Java都无法胜过C ++。我也不希望C ++大大超过Java。
juanchopanza 2014年

Answers:


92

std::list在C ++中,链表是一个链表,而java.util.ArrayList数组是一个链表。尝试更换std::liststd::vector。另外,请确保在打开优化的情况下进行编译。


4
@ realUser404对我来说,在这种情况下,按引用传递比较慢(我想是因为Point对象不那么大)。另外,您正在使用什么编译器?对我来说,使用优化(g++-4.9 -O2)进行编译时,原始C ++代码已经比原始Java代码更快。
布莱恩(Brian)

10
在Point结构中用int替换double可以使编译器生成更好的代码。
雅各布2014年

22
@Jakub好点。Java代码int与C ++代码的double比较不是一个公平的比较。
没人

4
@Jakub我的想法正好。数据结构错误加上数据类型错误。此外,为了帮助我们的朋友Peter,我认为每种语言都有自己的STL怪癖。要流利,需要具备图书馆知识和习语。
Sinthia V 2014年

3
您可能想详细说明std::list该程序的结构效率不如std::vector。(双向链接)列表上的基本操作(例如,迭代器的增量)需要比向量更多的周期仅仅是一个问题,还是使用从根本上来说慢于列表的事情(例如按索引访问元素) ?换句话说,这两个实现是否具有相同的渐进复杂度,而它们之间只是一个常数因子?
Marc van Leeuwen 2014年

89

更新:

对C ++的更改

  • 撰写如下:
    编译失败
  • 替换math.h => cmath
    27610毫秒
  • 添加-O3标志
    4416毫秒
  • 将std :: list替换为std :: vector
    2294毫秒
  • 将点替换为std :: pair
    2384毫秒
  • 使verifierNonPrise const正确
    2351毫秒
  • 将verifierNonPrise中的循环替换为std::find_if
    929毫秒
  • 用int代替double(使其等效于Java)
    549毫秒

对Java的更改

  • 如所写的
    3459毫秒
  • 更改verifierNonPrise提前返回
    368毫秒

Java与C ++

> javac HuitDames.java
> time java HuitDames
real    0m0.368s
user    0m0.436s
sys     0m0.042s    
> g++ -O3 -std=c++11 HuitDames.cpp
> time ./a.out
real    0m0.541s
user    0m0.539s
sys     0m0.002s

最终代码:

#include <iostream>
#include <vector>
#include <cmath>
#include <stdlib.h>
#include <chrono>
#include <algorithm>

using namespace std;

typedef std::pair<int, int>   Point;

#define LARGEUR_GRILLE 22
vector<Point> positions;


bool verifierNonPrise(Point const& emplacement) {
    return std::find_if(positions.begin(), positions.end(), [&emplacement](Point const& val){
        if (val.first != emplacement.first) {
            if ((val.second == emplacement.second) || (abs(val.second - emplacement.second) == abs(val.first - emplacement.first))) {
                return true;
            }
        }
        return false;
    }) == positions.end();
}

bool placerDame(int i) {
    bool bonnePosition = false;

    for (int j = 1; j <= LARGEUR_GRILLE && !bonnePosition; j++) {
        Point emplacement(i,j);
        positions.push_back(emplacement);
        if (verifierNonPrise(emplacement) && (i == LARGEUR_GRILLE || placerDame(i + 1))) {
            bonnePosition = true;
        }
        else {
            positions.pop_back();
        }
    }

    return bonnePosition;
}


int main()
{
    using std::chrono::system_clock;

    system_clock::time_point begin_time = system_clock::now();

    int i = 1;
    placerDame(i);
    for (vector<Point>::iterator it = positions.begin(); it!= positions.end(); it++) {
        cout << "(" << it->first << "; " << it->second << ")" << endl;
    }

    system_clock::time_point end_time = system_clock::now();

    long long elapsed_milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - begin_time).count();
    cout << "Duration (milliseconds): "
         << elapsed_milliseconds
         << std::endl;    
}

#include <algorithm>并且#include <chrono>丢失(没有它们就无法在我的编译器上编译)。同样,-O3和-Ofast在计时方面保持不变。有什么想法吗?
Florian Richoux 2014年

是时代Replace std::list with std::vectorReplace Point with std::pairMade verifierNonPrise const correct真正的不同或有差异只是测量不精确?
nwp

@FlorianRichoux:-Ofast启用了允许非标准行为的优化,但是在大多数情况下仍然表现合理(例如,a a to a(a a)*(a * a)优化。在这里根本没有机会导致这种情况可衡量的改进。
PlasmaHH

2
@Deduplicator:两者之间的速度差异(大部分)是神话。关于SO的大量文章。当您发现差异时,是因为您忘记致电sync_with_stdio
Martin York

1
@Deduplicator:输出量很小,我不希望速度有任何可测量的差异。刚刚尝试过(没有区别)。
马丁·约克

30

测试此版本,该版本使用C ++ 11功能进行了更新。在GCC 4.9.0中使用进行了测试-std=c++11。在Celeron 1.6 GHz,512 MB RAM上测试。

PC上的时间
原始:持续时间(毫秒):12658
第一个版本:持续时间(毫秒):3616
优化版本:持续时间(毫秒):1745

更改为:

  • 使用vector代替list 基准Stroustrup的话
  • 尽我们所能使用const,如果知道该值不变,则编译器可以进行更多优化。
  • 使用std :: pair代替Point。
  • 在常量迭代器中使用新的for循环。

资源:

#include <iostream>
#include <vector>
#include <chrono>
#include <iomanip>

using namespace std;

typedef std::pair<int, int> Point;

#define LARGEUR_GRILLE 22
vector<Point> positions;

bool verifierNonPrise(const Point& emplacement) {
    bool nonPrise = true;
    for (const auto& p : positions) {
        if (p.first != emplacement.first) {
            if (p.second == emplacement.second) {
                nonPrise = false;
            }
            if (abs(p.second - emplacement.second) ==
                abs(p.first - emplacement.first)) {
                nonPrise = false;
            }
        }
    }

    return nonPrise;
}

bool placerDame(int i) {
    bool bonnePosition = false;
    for (int j = 1; j <= LARGEUR_GRILLE && !bonnePosition; j++) {
        Point emplacement(i, j);
        positions.emplace_back(emplacement);
        if (verifierNonPrise(emplacement) &&
            (i == LARGEUR_GRILLE || placerDame(i + 1))) {
            bonnePosition = true;
        } else {
            positions.pop_back();
        }
    }

    return bonnePosition;
}

int main(int argc, char* argv[]) {
    std::chrono::system_clock::time_point begin_time =
        std::chrono::system_clock::now();

    positions.reserve(LARGEUR_GRILLE);

    placerDame(1);
    for (const auto& p : positions) {
        cout << "(" << p.first << "; " << p.second << ")" << endl;
    }

    std::chrono::system_clock::time_point end_time =
        std::chrono::system_clock::now();
    long long elapsed_milliseconds =
        std::chrono::duration_cast<std::chrono::milliseconds>(
            end_time - begin_time).count();
    std::cout << "Duration (milliseconds): " << elapsed_milliseconds
              << std::endl;

    return 0;
}

一些更深刻的变化。

更改包括:

  • 尽早返回。女王不能一经放置。
  • 返回一个简单的Point类。
  • 使用find_if算法搜索皇后位置。

来源(一些建议已更新):

#include <algorithm>
#include <iostream>
#include <vector>
#include <chrono>
#include <iomanip>

using namespace std;

struct Point {
    int x, y;
};

#define LARGEUR_GRILLE 22
vector<Point> positions;

bool verifierNonPrise(const Point& emplacement) {
    return find_if(positions.cbegin(), positions.cend(), [&emplacement](const Point& p) {
               return (p.x != emplacement.x &&
                       (p.y == emplacement.y ||
                        abs(p.y - emplacement.y) == abs(p.x - emplacement.x)));
           }) == positions.cend();
}

bool placerDame(int i) {
    for (int j = 1; j <= LARGEUR_GRILLE; j++) {
        Point emplacement{i, j};
        positions.push_back(emplacement);
        if (verifierNonPrise(emplacement) &&
            (i == LARGEUR_GRILLE || placerDame(i + 1))) {
            return true;
        } else {
            positions.pop_back();
        }
    }
    return false;
}

int main(int argc, char* argv[]) {
    std::chrono::system_clock::time_point begin_time =
        std::chrono::system_clock::now();

    positions.reserve(LARGEUR_GRILLE);

    placerDame(1);
    for (const auto& p : positions) {
        cout << "(" << p.x << "; " << p.y << ")" << endl;
    }

    std::chrono::system_clock::time_point end_time =
        std::chrono::system_clock::now();
    long long elapsed_milliseconds =
        std::chrono::duration_cast<std::chrono::milliseconds>(
            end_time - begin_time).count();
    std::cout << "Duration (milliseconds): " << elapsed_milliseconds
              << std::endl;

    return 0;
}

和?与原始版本相比,它的性能如何?
juanchopanza 2014年

2
不知道为什么std::pair吗?从设计的角度来看,绝对是您要避免的事情。我也怀疑使用是否emplace_back会产生重大差异;更微调。(std::vector无疑,使用和通过引用是最大的胜利。)
James Kanze 2014年

在我的机器上原始4296毫秒。NetVipeC版本682。可能还有更多改进,但已经有了很大的改进
Benjamin Trent

@JamesKanze是的,在这种情况下emplace_back什么也得不到,我改变了,因为认为emplacement方法中的变量placerDame仅用于在vector看到对的调用时插入和撤消verifierNonPrise,但忘记了emplace_back。原因std::pair是没有理由为STD所涵盖的内容创建类,仅是需要维护更多的代码,就需要测试更多的代码,即使这样做是微不足道的,并且std::make_pair(在某些编译器中,仅对这两种类型进行了一次分配),在这种情况下并不多,但是创建100万对将有所不同。
NetVipeC 2014年

3
@NetVipeC编译器不应对std::vector此处以外的任何内容进行任何分配。使用一个类会更干净,并且不会更慢。或者因为您使用的是C ++ 11,所以具有列表初始化的结构。当然,std::pair这里是混淆的,因为成员不是第一和第二,而是xand y(具有明确的语义);std::pair方便进行快速实验,但在严格的代码中使用它是一种反模式。
James Kanze 2014年

19

将托管的动态编译语言(如Java)与静态编译的语言(如C ++)进行比较非常困难。

从某种意义上讲,您将始终在比较苹果和橙子,因为它们在概念上是非常不同的。它从使用标准库(ArrayList与std :: list / vector)开始,它们甚至可能在两种语言中看起来相似的情况下,也可能具有截然不同的性能特征。

然后,Java中的微基准存在一个固有的问题(Java中的简短测试总是较慢,因为JIT在决定要编译的内容和方式之前会观察程序流)。C ++的编译器选项也是如此,即使源代码的结构(独立编译和链接的类与单个文件源)也可以产生显着差异(因为它改变了C ++编译器对其他类的“了解”量) 。

接下来是内存管理,垃圾回收与手动内存管理的一般差异(智能指针等仍被视为手动内存管理)。

更不用说一般的语言差异,例如您需要在C ++中显式声明一个虚拟方法,而在Java中,每个成员方法默认情况下都是虚拟的(确定在运行时是否真正是虚拟的留给了VM)。

尽管存在所有这些差异,但总有一种语言比另一种语言具有更大优势的情况。一个范围非常有限的简单测试(例如此处的测试)对每种语言的整体介绍很少。

人们经常会忽略的另一点是:语言的生产率如何-速度并不是一切(尽管在某些情况下仅以执行速度来看,其竞争能力并不强,但脚本语言在某些领域却表现得如此出色)。缺乏性能可能会造成严重后果,但生产率可能会降低。


2
我认为问题的关键在于,OP在特定情况下原本希望C ++更快,但惊讶地发现它慢得多。这里没有苹果或橙子。
juanchopanza 2014年

7
@juanchopanza然后,任务的标题应该是“如何改进此C ++代码”,将其放置在codereview上可能会更好。尽管其他答案很好地涵盖了可能的优化,但它们都忽略了本质上无与伦比的方面-某些优化建议使结果更加不可比。一件正确的事是将C ++版本更改为vector,因为它与ArrayList更相似。但其他寄托都只是增加了两个实现它的区别比较苹果和橘子。
Durandal 2014年

@Durandal-将点坐标从double更改为int使其更类似于Java示例。而且可能会有很大的预制差异。
雅各布2014年

@Jakub虽然我全心全意地同意您使用相同的数据类型,但是我一般的“从苹果到橘子”的意思是针对优化尝试,例如“尽早返回。无法放置女王之后”。甚至从根本上改变了逻辑。我并没有仔细检查一下OP的原始代码(如果它最初与原始代码相似),所以我什至从未注意到过这种错误存在于原始C ++版本中。当他说完全相同的算法时,我完全相信没有这种根本性(无动机的)差异。
Durandal 2014年

@Durandal我的意思是,“您的正确的选择是将C ++版本更改为vector,因为它与ArrayList更相似。但是,其他所有事情都只是增加了将苹果与橘子进行比较的两个实现之间的差异。” 并非完全正确。由于集成数据类型完整,因此Java优化器可能会生成更好/更快的代码。答案/提议的解决方案之一包括此更改。一般而言,我无意与您对优化和基准测试的意见产生分歧。
雅各布2014年

3

我可能会在这里大吃一惊,但只需将Java逐行转换为C ++,甚至不使用const引用参数或任何类似的东西,就可以看到C ++的运行速度几乎是Java的两倍。如果有的话,所有“语法优化”嵌入等效果都不大。

rep ~/Documents $ g++ -O3 Queen.cpp
rep ~/Documents $ javac Queen.java 
rep ~/Documents $ time java Queen 
(1; 1)
(2; 3)
(3; 5)
(4; 2)
(5; 4)
(6; 10)
(7; 14)
(8; 17)
(9; 20)
(10; 13)
(11; 19)
(12; 22)
(13; 18)
(14; 8)
(15; 21)
(16; 12)
(17; 9)
(18; 6)
(19; 16)
(20; 7)
(21; 11)
(22; 15)

real    0m4.806s
user    0m4.857s
sys     0m0.067s
rep ~/Documents $ time ./a.out
(1; 1)
(2; 3)
(3; 5)
(4; 2)
(5; 4)
(6; 10)
(7; 14)
(8; 17)
(9; 20)
(10; 13)
(11; 19)
(12; 22)
(13; 18)
(14; 8)
(15; 21)
(16; 12)
(17; 9)
(18; 6)
(19; 16)
(20; 7)
(21; 11)
(22; 15)

real    0m2.131s
user    0m2.113s
sys     0m0.000s
rep ~/Documents $

Queen.java(翻译成英文)

import java.awt.Point;
import java.util.ArrayList;
import java.util.List;

public class Queen {

    private static List<Point> positions = new ArrayList<>();
    private static final int GRID_SIZE = 22;

    public static void main(String[] args) 
    {
        int i = 1;
        placeQueen(i);
        for (Point point : positions) 
        {
            System.out.println("(" + point.x + "; " + point.y + ")");
        }
    }

    private static boolean placeQueen(int i) 
    {
        boolean bIsGoodPos = false;
        for (int j = 1; j <= GRID_SIZE && bIsGoodPos == false; j++) 
        {
            Point emplacement = new Point(i, j);
            positions.add(emplacement);
            if (verifyPos(emplacement) && (i == GRID_SIZE || placeQueen(i + 1))) 
            {
                bIsGoodPos = true;
            }
            else 
            {
                positions.remove(i - 1);
            }
        }

        return bIsGoodPos;
    }

    private static boolean verifyPos(Point position) 
    {
        boolean bIsSafe = true;
        for (Point point : positions) 
        {
            if (!point.equals(position)) 
            {
                if (position.y == point.y) 
                {
                    bIsSafe = false;
                }
                if (Math.abs(position.y - point.y) == Math.abs(position.x - point.x)) 
                {
                    bIsSafe = false;
                }
            }
        }

        return bIsSafe;
    }
}

皇后乐队

#include <cmath>
#include <vector>
#include <iostream>

using namespace std;

struct Point
{
    int x, y;
    Point(int ii, int jj):x(ii), y(jj){}
};

vector<Point> positions;
int GRID_SIZE = 22;


bool verifyPos(Point position) 
{
    bool bIsSafe = true;
    for(int i = 0; i < positions.size(); ++i) 
    {
        Point point = positions[i];
        if(point.x != position.x || point.y != position.y) 
        {
            if(position.y == point.y) 
            {
                bIsSafe = false;
            }
            if(abs(position.y - point.y) == abs(position.x - point.x)) 
            {
                bIsSafe = false;
            }
        }
    }

    return bIsSafe;
}

bool placeQueen(int i) 
{
    bool bIsGoodPos = false;
    for(int j = 1; j <= GRID_SIZE && bIsGoodPos == false; j++) 
    {
        Point p(i, j);
        positions.push_back(p);
        if(verifyPos(p) && (i == GRID_SIZE || placeQueen(i + 1))) 
        {
            bIsGoodPos = true;
        }
        else 
        {
            positions.pop_back();
        }
    }
    return bIsGoodPos;
}


int main(void) 
{
    int i = 1;
    placeQueen(i);
    for(int i = 0; i < positions.size(); ++i) 
    {
        Point p = positions[i];
        cout << "(" << p.x << "; " << p.y << ")" << endl;
    }

    return 0;
}

2

如果使用位图,C ++可以在21毫秒内完成操作(在旧版i7-860内核上)。对于计时运行,我注释掉了showSoln()调用,因为棋盘的图形显示花费的时间是找到解决方案的时间的两倍。

#include <iostream>
#include <iomanip>
#include <fstream>
#include <omp.h>                        //omp_get_wtime() is my favorite time function
using namespace std;

static const unsigned n(22);            //size of board
static_assert(n<32,"use long unsigned for bit masks if n > 32");
static const unsigned mask((1U<<n)-1);  //n wide bitmask with every bit set

void showSoln(unsigned* selCol, unsigned numSoln) {     //show a solution
    cout << "\nsolution " << numSoln << '\n';
    for (unsigned row=0; row<n; ++row) {
        for (unsigned col=0; col<n; ++col)
            cout << (col==selCol[row]? " Q": " .");
        cout << '\n';
    }
}

void main() {
    //for each row bitmasks that show what columns are attacked, 1 bit means attacked
    unsigned ulAttack[n];           //cols attacked from upper left, shift right for next row
    unsigned upAttack[n];           //cols attacked from straight up, same for next row
    unsigned urAttack[n];           //cols attacked from upper right, shift left for next row
    unsigned allAttack[n];          //OR of all attacks on given row
    allAttack[0]= ulAttack[0]= upAttack[0]= urAttack[0]= 0; //no attacks on row 0
    unsigned row= 0;                //the row where now placing a queen 
    unsigned selCol[n];             //for each row the selected column
    unsigned numSoln= 0;            //count of soutions found
    double wtime= omp_get_wtime();
    for (;;) {                                          //loop until find 1st (or all) solutions
        if (allAttack[row]!=mask) {                     //if 'row' has a column not attacked
            unsigned long bit;
            _BitScanForward(&bit,~allAttack[row]);      //find lowest column not attacked
            //note - your compiler may have a different intrinsic for find lowest set bit
            selCol[row]= bit;                           //remember selected column for this row
            unsigned move= 1U<<bit;                     //convert selected column to bitmask
            allAttack[row]|= move;                      //mark column attacked to prevent re-use
            if (row==n-1) {                             //if move in last row have a soln
                ++numSoln;
                showSoln(selCol,numSoln);
                break;                                  //remove this break if want all solutions
            } else {                                    //no solution yet, fill in rows below
                unsigned nrow= row+1;                   //next row
                //from attacks on this row plus 'move' decide attacks on row below
                ulAttack[nrow]= (ulAttack[row] | move) >> 1;
                upAttack[nrow]= (upAttack[row] | move);
                urAttack[nrow]= ((urAttack[row] | move) << 1) & mask;
                allAttack[nrow]= ulAttack[nrow] | upAttack[nrow] | urAttack[nrow];
                row= nrow;                              //go to next row
            }
        } else {                //else move on 'row' is impossible so backtrack
            if (!row)           //if backtrack from row 0 have found all solutions
                break;
            --row;              //try next move in prior row
        }
    }
    wtime= omp_get_wtime() - wtime;
    cout << "numSoln= " << numSoln << '\n';
    cout << "time= " << wtime*1000 << " msec\n";
}

1

同样,没有理由为坐标使用浮点/双精度类型。

如果不强制在C ++中调用浮点abs库调用,则应该获得性能

Java将Point坐标存储为整数。get函数返回的是double,但是用Java和c ++进行优化可能更容易。


0

似乎对于不需要太多内存访问和密集计算的代码,Java和C ++之间的差异很小。但是在相反的情况下,差异看起来惊人:

test.java

import java.lang.String;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Scanner;

public class test{
    private static Random gna=new Random();

    public static double new_value(double value){
        if (value<0.5) value=0;
        return value*value;
    }

    public static void main(String[] args) {
        long start_time = System.currentTimeMillis();   
        List<Double> ze_list=new ArrayList();
        for (int i=0;i<1e8;i++){
            double temp=new_value(gna.nextDouble());
            ze_list.add(temp);
        }
        long end_time = System.currentTimeMillis();
        System.out.println("Time (s) :"+ ((end_time-start_time)/1000));
        Scanner input = new Scanner(System.in);
        String inputval = input.next();
    }
}

并将其与test.cpp进行比较:

#include <iostream>
#include <vector>
#include <ctime>
#include <random>
using namespace std;

static default_random_engine dre1(time(0));
static uniform_real_distribution <double> urd1(0, 1);

static double new_value(double value){
    if (value<0.5) value=0;
    return value*value;
}

int main(void){
        time_t tbegin,tend;
        double texec=0;
        tbegin=time(NULL);
        vector<double> ze_list;
        for (int i=0;i<1e8;i++){
            double temp=new_value(urd1(dre1));
            ze_list.push_back(temp);
        }
        tend=time(NULL);
        texec=difftime(tend,tbegin);
        cout << "\nTime (s) " << texec << " s\n";
        int val=0;
        cin >> val;
    return 0;
}

我刚刚在Mac上进行了测试:

  • Java版本用了90年代,需要3.77 Go
  • C ++程序耗时2秒,仅需770 Mo

也许有可能提高Java性能,但我不知道如何做到。


-1

Java将对象作为引用传递给方法,而这些引用按值传递,但是C ++按值传递对象。

您应该更改C ++代码以使其与Java相同(C ++中的传递指针而不是传递对象):

bool verifierNonPrise(Point* emplacement) // The correct way for passing arguments.
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.