C++builder中的人工智能(3)质数测试大比拼

AI追求性能,看看C++builder的性能如何。
质数基准测试有助于比较不同编程语言中相同代码的性能。在这次测试中,我们将重点关注两个“兄弟”——C++ Builder和Delphi,它们都是RAD Studio中的强大编程语言。

目录

  1. 系统描述
  2. C++ Builder中的质数计算
  3. Delphi中的质数计算
  4. Delphi和C++ Builder在32位和64位系统上的结果
  5. 比较
  6. 结论

1. 系统描述

我们在这里使用的测试电脑配置如下:

操作系统: Windows 10 64位

配置1:

处理器:AMD Ryzen 7 1800X (3.6 GHz),8核心,16逻辑处理器。

配置2:

Haswell:处理器Intel(R) Core(TM) i7-4790 CPU @ 3.60GHz,3601 MHz,4核心,8逻辑处理器。

配置3:

处理器:AMD Ryzen 5 3600X 6核心处理器,3793 MHz,6核心,12逻辑处理器。

  • 注意:所有测试都是在单核上进行的,不考虑核心数量。

2. C++ Builder中的质数计算

C++ Builder支持Win32、Win64、Android和iOS的编译器。它拥有增强型CLANG C/C++编译器和Borland C/C++编译器。它还具有现代、高生产力的RAD Studio IDE、调试工具和企业级连接性,以加速跨平台UI开发。你可以轻松开发基于GUI的应用,因为它包含了获奖的VCL框架,用于高性能的原生Windows应用,以及功能强大的FireMonkey (FMX)框架,用于跨平台UI。还有一个免费的C++ Builder社区版,供学生、初学者和初创企业使用,但功能有限。

在这个测试中,我们将使用之前在C++ Builder中使用过的相同代码。

下面是cpptest.cpp,是经过优化的,优化的是is_prime()和count_prime()。

// Contains C++ version of 'count_primes'
#if defined(USE_SQRT)
#include <math.h>
#endif
 
#if 0
static bool is_prime(unsigned x)
{
  if (x < 2)
    return false;
 
  if (x % 2 == 0)
    return (x == 2);
 
#if defined(USE_SQRT) // Use 'sqrt' to calculate cut-off
  int q = sqrt(static_cast<double>(x));
  for (int i=3; i<=q; i+= 2)
#else
  for (int i=3; (i*i) <= x; i+= 2)
#endif
    if (x % i == 0)
      return false;
 
  return true;
}
#else
 
bool is_prime(unsigned n)
{
  if (n <= 3)
    return n > 1;
 
  if (n % 2 == 0 || n % 3 == 0)
    return false;
 
  for (int i=5; i*i<=n; i+=6)
    if (n%i == 0 || n%(i+2) == 0)
      return false;
 
  return true;
}
 
#endif
 
int count_primes(unsigned maxN)
{
  unsigned int res=0;
  for (unsigned i=2; i<=maxN; i++)
    if (is_prime(i))
      res++;
 
  return res;
}
test.cpp

test.cpp 文件是一个用于链接和测试 C++ 以及 Delphi/Pascal 代码的示例。这个文件的作用是展示如何在 C++ Builder 环境中同时使用 C++ 和 Delphi/Pascal 代码进行质数计算的性能测试。以下是对 test.cpp 文件内容的解释和润色:

#include <iostream>
#include <chrono>
#include <assert.h>

#if defined(__BORLANDC__)
#include "pastest.hpp"
#pragma link "pastest"
#pragma link "cpptest"
#endif

int count_primes(unsigned maxN); // 声明在 cpptest.cpp 中定义的 count_primes 函数

const unsigned MAX_N = 1000000;

#if defined(__BORLANDC__)
void testPas() {
    auto start = std::chrono::steady_clock::now();
    int count = countPrimes(MAX_N);
    auto end = std::chrono::steady_clock::now();
    auto diff = end - start;
    std::cout << "Pas: " << std::chrono::duration<double, std::milli>(diff).count() << " ms" << std::endl;
    assert(count == 78498);
}
#endif

void testCpp() {
    auto start = std::chrono::steady_clock::now();
    int count = count_primes(MAX_N);
    auto end = std::chrono::steady_clock::now();
    auto diff = end - start;
    std::cout << "C++: " << std::chrono::duration<double, std::milli>(diff).count() << " ms" << std::endl;
    assert(count == 78498);
}

int main(int argc, char* argv[]) {
#if defined(_WIN64)
    std::cout << "WIN64";
#elif defined(_WIN32)
    std::cout << "WIN32";
#endif

#if defined(__INTEL_LLVM_COMPILER)
    std::cout << " Intel ";
#elif defined(_MSC_VER)
    std::cout << " Microsoft ";
#elif defined(__BORLANDC__)
    std::cout << " EMB ";
#endif
std::cout << "\n";

int count = argc > 1 ? atoi(argv[1]) : 1;

#if defined(__BORLANDC__)
    for (int i = 0; i < count; ++i)
        testPas();
#endif

    for (int i = 0; i < count; ++i)
        testCpp();
}

文件解释:

  1. 头文件包含

    • <iostream>:用于输入输出操作。
    • <chrono>:用于时间测量。
    • <assert.h>:用于断言,确保程序的正确性。
  2. 条件编译

    • 如果定义了 __BORLANDC__(即在 Borland C++ 编译器中),则包含 Delphi/Pascal 代码的头文件,并链接相关的 Pascal 单元。
  3. 函数声明

    • count_primes:在 cpptest.cpp 中定义的函数,用于计算质数。
  4. 测试函数

    • testPas:测试 Delphi/Pascal 代码的性能。
    • testCpp:测试 C++ 代码的性能。
  5. 主函数

    • 根据操作系统和编译器输出相关信息。
    • 根据命令行参数决定测试次数,如果未提供参数,则默认为1次。
    • 调用 testPas 和 testCpp 函数进行测试。

 以下是一个 build.bat 批处理文件的示例,它用于编译 Delphi 和 C++ 文件,并将它们链接为 test32.exetest64.exe。在编译过程中,我们使用了 -ffast-math-Xdriver-mavx 参数以及 -O2 优化选项。

@echo off
setlocal

REM Batch file to build 32-bit and 64-bit versions of Pascal/C++ countPrime
dcc32.exe -jp -h -$O+ -$D0 -$L- -$Y- pastatest.pas
bcc32c.exe -tJ -O2 -ffast-math -Xdriver-mavx -Scpptest.cpp
bcc32c.exe -tJ -O2 -ffast-math -Xdriver-mavx -c cpptest.cpp
bcc32c.exe -tJ -O2 -otest32.exe test.cpp

dcc64.exe -jp -h -$O+ -$D0 -$L- -$Y- pastatest.pas
bcc64.exe -tJ -O2 -ffast-math -c cpptest.cpp
bcc64.exe -tJ -O2 -otest64.exe test.cpp

文件解释:

  1. @echo off:关闭命令的回显,使批处理文件运行时不显示执行的命令。

  2. setlocal:开始局部环境块,防止更改全局环境。

  3. REM:注释,说明这是一个用于编译 32 位和 64 位版本的 Pascal/C++ 质数计数程序的批处理文件。

  4. dcc32.exe:Delphi 32 位编译器,用于编译 Pascal 代码(pastest.pas)。

  5. bcc32c.exe:C++ 32 位编译器,用于编译 C++ 代码(cpptest.cpptest.cpp)。

  6. -tJ:指定输出为 Windows 可执行文件。

  7. -O2:优化级别,提高代码执行效率。

  8. -ffast-math:允许编译器使用非标准的、但更快的数学运算。

  9. -Xdriver:传递参数给驱动程序。

  10. -mavx:允许编译器使用 AVX 指令集,提高性能。

  11. -S:指示编译器不生成输出文件,只进行编译。

  12. -c:编译但不链接。

  13. -otest32.exe-otest64.exe:指定输出文件的名称。

 

3. Delphi中的质数计算

Delphi是另一种编译型(非解释型)的快速编程语言,支持Windows、Android、iOS、Mac-OS和Linux操作系统的32位和64位系统。C++ Builder和Delphi都使用RAD Studio IDE,并且都拥有VCL和FMX UI框架。

这是我们测试的修改后的Delphi代码。

unit pastest;
 
interface
 
function countPrimes(MaxN: FixedUInt): integer;
 
implementation
 
// Port of code from https://en.wikipedia.org/wiki/Primality_test#Python_code
function isPrime(n: FixedUInt): Boolean;
begin
  if (n <= 3) then
    Exit(n > 1);
 
  if (n mod 2 = 0) or (n mod 3 = 0) then
    Exit(False);
    
  var I: FixedUInt := 5;
  while ((I*I) <= n) do
  begin
    if (n mod i = 0) or (n mod (I+2) = 0) then
      Exit(False);
    Inc(I, 6);
  end;
 
  Exit(True);
end;
 
function countPrimes(MaxN: FixedUInt): integer;
begin
  Result := 0;
  for var i:FixedUInt := 2 to MaxN do
  begin
    if isPrime(i) then
      Inc(Result);
  end;
end;
 
end.

 

4. Delphi和C++ Builder在32位和64位系统上的结果

要编译C++和Delphi (Pascal)文件:

  1. 运行RAD Studio命令提示符。
  2. 转到包含上述代码的项目文件夹。
  3. 运行‘build.bat’来编译.pas和.cpp文件到test32.exe和test64.exe文件。
  4. 运行‘test32.exe 5’,这里的5参数表示运行1M次测试5次。
  5. 运行‘test64.exe 5’,这里的5参数表示运行1M次测试5次。

以下是在AMD Ryzen 7 1800X的配置1上的测试结果。

 这些是布鲁诺·巴贝(Bruneau Babet)在配置2下,使用Haswell处理器Intel(R) Core(TM) i7-4790 CPU @ 3.60GHz的测试结果。

 

 这些是布鲁诺·巴贝(Bruneau Babet)使用配置2(Haswell处理器Intel(R) Core(TM) i7-4790 CPU @ 3.60GHz)对Intel C++、微软MS C++、Embarcadero C++ Builder和Delphi进行测试的结果。

以下这些结果同样来自布鲁诺·巴贝(Bruneau Babet),他在配置3下进行了测试,使用的是AMD Ryzen 5 3600X六核心处理器,频率为3793 MHz,拥有6个物理核心和12个逻辑处理器。

5. 比较

C++ Builder与Delphi的最终较量,32位结果如下表所示:

64位结果如下表所示:

结果显示,在32位测试中,C++ Builder以大约3%的速度优势获胜,在64位测试中,C++ Builder以大约8%的速度优势获胜

6. 结论

C++是最快的编程语言之一,Delphi也是我们知道的另一种快速编程语言,它们都是非解释型(编译型)的原生编程语言。我个人在多年前(大约在98-2000年)对Pascal代码进行过测试,所有测试都显示C++ Builder比Delphi快,而在这篇文章中,我们再次找到了测试这两种出色的编程语言的机会。

在这次较量中,C++ Builder在32位测试中以大约3%的速度优势获胜,在64位测试中,C++ Builder以大约8%的速度优势获胜

实际上,我没想到会是这样,我预期它们之间的差异会更大,因为我在多年前进行的测试。在这里,如果我们看结果,最新的Delphi也是赢家!我认为这是因为过去十年的改进,它证明了它和C++一样快,并且更强大。这表明Delphi在编译方面在过去几年取得了巨大的进步,它在32位编译方面表现非常好,64位编译也很棒。

这些结果是在单核上运行的,不考虑核心数量。实际上,这个质数测试在运行时有一些函数,虽然不是全部,但我认为这些测试足以提供一些关于编程语言速度的信息。可能还会有更多的测试,包括更多的数学、2D图形、3D图形、GUI元素。我不认为Delphi和C++ Builder之间会有差异,对图形也不是很确定。

我们还对上述新优化的质数测试进行了一些测试,使用了Intel和Visual C++编译器,C++编译器的结果大致相同,变化非常小。

总之,这些结果令人惊讶地意味着你可以在所有情况下使用C++ Builder和Delphi编程语言,包括繁重的数学、AI技术、ML应用、图像处理、并行编程、工程仿真、游戏等。在这些测试中可能只有3-8%的差异。

我们能否在Delphi和C++ Builder上进一步加速?当然可以!我们只使用了单核,我们还测试了并行编程,它使用了所有核心,我们还可以结合CPU和GPU来加速这些结果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

caridle

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值