我需要编写一个程序(大学项目)来解决(近似)NP难题。 它是线性排序问题的变体。 一般来说,我将有非常大的输入(如图),并将尝试找到最佳解决方案 (基于将对每个解决方案进行“评级”的功能)
如果我用C风格的代码(一个主要和功能)写这个会有区别吗? 或构建一个Solver类,创建一个实例并从main(类似于Java)调用'run'方法
此外,每次迭代都会有很多浮点运算。
谢谢!
答案 0 :(得分:58)
没有
最大的性能提升/缺陷将取决于您实施的算法,以及您执行的不必要的工作量(不需要的工作可能是重新计算可能已缓存的先前值,使用过多的malloc / free和使用内存池, 按值而不是引用传递大的不可变数据
答案 1 :(得分:19)
最佳代码的最大障碍不再是语言(对于正确编译的语言),而是程序员。
答案 2 :(得分:9)
不,除非您使用虚拟功能。
编辑:如果您有需要运行时动态的情况,那么是的,虚拟函数与手动构造的if-else
语句一样快或快。但是,如果您在方法前面放入virtual
关键字,但实际上并不需要多态性,那么您将支付不必要的开销。编译器不会在编译时对其进行优化。我只是指出这一点,因为它是C ++的一个特性,打破了“零开销原则”(引用Stroustrup)。
作为旁注,因为你提到大量使用fp数学:
-mfpmath=sse
,{{ 1}}和-ffast-math
(最后两个是'稍微危险',这意味着他们可以在边缘情况下给你奇怪的结果以换取速度。第一个会降低精度一点 - 你有64-比特加倍而不是80比特 - 但这种额外的精度通常是不需要的。)这些标志对于C和C ++编译器同样有效。
-mrecip
可以提高速度。这是因为真正的INFINITY
必须由处理器作为特殊情况处理。
答案 3 :(得分:6)
经验法则 - 在知道要优化的内容之前不要进行优化。所以从C ++开始,有一些工作原型。然后对其进行分析并重新组装瓶颈。但正如其他人所指出的,选择的算法将比语言产生更大的影响。
答案 4 :(得分:6)
在谈到性能时,可以用C ++完成C语言中的所有操作。 例如,已知虚拟方法“慢”,但如果它确实存在问题,您仍然可以使用C语言。
C ++还带来了模板,与使用void*
进行泛型编程相比,性能更高。
答案 5 :(得分:3)
Solver
类将被构造一次,我接受它,并且run
方法执行一次......在这种环境中,你不会看到差异。相反,这里有一些需要注意的事项:
内存管理非常昂贵。如果你需要做很多小malloc()
秒,操作系统会吃你的午餐。如果您知道自己将很快再次做同样的事情,请尽一切努力重新使用您创建的任何数据结构!
实例化类通常意味着......分配内存!同样,实例化一些对象并重新使用它们几乎没有成本。但要注意创建对象只是为了将它们拆除并在不久之后重建它们!
在问题允许的范围内,为您的架构选择正确的浮点风格。 double
最终可能会比float
更快,尽管它需要更多内存。你应该尝试微调这个。理想情况下,您将使用#define
或typedef
来指定类型,以便在一个位置轻松更改。
整数计算可能比浮点更快。根据数据的数值范围,您还可以考虑使用被视为定点小数的整数。如果你需要3个小数位,你可以使用int
s并只考虑它们“毫位”。你必须记住在除法和乘法之后移位小数......但没什么大不了的。当然,如果你使用基本算术之外的任何数学函数,那当然会消除这种可能性。
答案 6 :(得分:1)
由于两者都已编译,并且编译器现在非常擅长如何处理C ++,我认为唯一的问题是来自优化代码的程度。我认为在C ++中编写更慢的代码会更容易,但这取决于你的模型最适合的样式。
当谈到它时,我怀疑会有任何真正的区别,假设两者都写得很好,你使用的任何库,它们的编写得好,如果你在同一台计算机上进行测量。
答案 7 :(得分:1)
只要您不使用任何虚拟功能等,您就不会注意到任何可观的性能差异。早期的C ++被编译为C语言,因此只要您知道这会产生任何可观的开销(例如使用虚函数)的精确点,您就可以清楚地计算出差异。
此外,我想要注意,如果使用STL和Boost库,使用C ++可以获得很多好处。特别是STL提供了最重要的数据结构和算法的高效且经过验证的实现,因此您可以节省大量的开发时间。
实际上它还取决于您将使用的编译器以及它将如何优化代码。
答案 8 :(得分:1)
与文件输入和算法本身相比,函数调用与成员函数调用开销不太可能是限制因素。 C ++ iostreams不一定是超高速。如果你真的在优化,C有'限制',在C ++中,内联函数调用更容易。总的来说,C ++提供了更多用于清晰地组织代码的选项,但是如果它不是一个大程序,或者你只是以类似的方式编写它,无论是C还是C ++,那么C库的可移植性就变得更加重要。 / p>
答案 9 :(得分:1)
首先,使用C ++编写并不意味着使用OOP,请查看STL算法。 第二,C ++在运行时甚至可以稍快一些(与C相比,编译时间可能会很糟糕,但这是因为现代C ++往往很大程度上依赖于对编译器负责的抽象)。
编辑:好的,请参阅Bjarne Stroustrup的discussion of qsort and std::sort以及常见问题解答提及的文章(Learning Standard C++ as a New Language),其中他表明C ++风格的代码不仅可以更短并且更具可读性(因为更高的抽象),但也更快一些。
答案 10 :(得分:1)
另一方面:
C ++模板可以是生成特定类型/的优秀工具 优化的代码变体。
例如,C qsort
需要对比较器进行函数调用,而std::sort
可以内联传递的函子。当比较和交换本身便宜时,这可以产生显着的差异。
请注意,您可以使用一系列定义或代码生成器或手动生成针对各种类型优化的“自定义qsorts” - 您也可以使用C进行这些优化,但成本要高得多。
(它不是一般武器,模板仅在特定情况下有用 - 通常是单个算法应用于不同的数据类型或注入不同的小块代码。)
答案 11 :(得分:0)
好的答案。我会这样说:
使算法在其正式结构方面尽可能高效。
C ++会像C一样快,除了它会诱使你做蠢事,比如构建你不需要的对象,所以不要拿诱饵。像STL容器类和迭代器之类的东西可能看起来像是最新的和最好的东西,但它们会在热点中杀死你。
即便如此,在反汇编级别单步执行。你应该看到它直接解决你的问题。如果它花费大量的周期进入和退出例程,请尝试一些内联(或宏)。如果它徘徊在内存分配和释放中,在大多数情况下,停止它。如果它有内部循环,其中循环开销很大,请尝试展开循环。
这就是你如何尽可能快地完成它。
答案 12 :(得分:0)
我肯定会使用C ++。如果你小心你的设计并避免在热点内部创建繁重的对象,你不应该看到任何性能差异,但代码将更容易理解,维护和扩展。
明智地使用模板和类。通过引用传递对象来避免不必要的对象创建。如果需要,避免过多的内存分配,在热点之前分配内存。在内存指针上使用restrict关键字,以便在指针重叠或不重合时告诉编译器。
就优化而言,要特别注意内存对齐。假设您正在使用英特尔处理器,您可以使用向量指令,前提是您通过编译指示告诉编译器有关内存对齐和别名指针的信息。您也可以直接通过内在函数使用向量指令。
你也可以使用模板自动创建热点代码,如果你有不同大小的短循环之类的东西,让编译器优化它。要了解性能并深入了解瓶颈,英特尔vtune或oprofile非常有用。
希望有所帮助
答案 13 :(得分:0)
我做了一些DSP编码,有时还会转向使用汇编语言。我会说使用C或C ++,任何一个,并准备好在需要时使用汇编语言,特别是利用SIMD指令。