[fpc-pascal] How does FPC perform in the FASTEST Computer Language Race

Ryan Joseph genericptr at gmail.com
Sat Jul 10 18:46:21 CEST 2021



> On Jul 10, 2021, at 4:16 AM, Guillermo via fpc-pascal <fpc-pascal at lists.freepascal.org> wrote:
> 
> Hi,
> 
> I remember years ago a similar test in a web page.  Pascal was way low
> in the list, even below Java and Python! but we (in a forum) found that
> it wasn't Pascal fault: most versons program were optimised in code
> while Pascal used brute force (also compiling using -O3 made it way
> faster than the web proclaimed so we suspect they used -O- or even
> worse a relic compiler [Turbo Pascal 1?]). Once fixed it was almost
> unoticeably behind C in both FPC and Delphi (Delphi result was a bit
> faster).

Here's the C++ version that won. Looks like the magic comes from constexpr, which I don't understand very well in C++ except that it's a constant expression. Can anyone explain how constexpr works here?

// ---------------------------------------------------------------------------
// PrimeCPP_CONSTEXPR.cpp : Taking advantage of compiler optimizing constants
// ---------------------------------------------------------------------------

#include <chrono>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <thread>
#include <vector>

#include "Sieve.h"

using namespace std;
using namespace std::chrono;

struct RESULTS
{
    unsigned long long upTo;
    int count;
};

constexpr RESULTS resultsDictionary[] = {
    {10LL, 4},   // Historical data for validating our results - the number of primes
    {100LL, 25}, // to be found under some limit, such as 168 primes under 1000
    {1000LL, 168},
    {10000LL, 1229},
    {100000LL, 9592},
    {1000000LL, 78498},
    {10000000LL, 664579},
};

constexpr int find(const unsigned long long val)
{
    for (const auto d : resultsDictionary)
    {
        if (d.upTo == val)
            return d.count;
    }
    return -1;
}

constexpr int countPrimes(const Sieve &sieve)
{
    return sieve.count();
}

constexpr bool validateResults(const Sieve &sieve)
{
    const auto sieveSize = sieve.size();
    const auto result = find(sieveSize);
    if (-1 == result)
        return false;
    return result == countPrimes(sieve);
}

void printResults(const Sieve &sieve, bool showResults, double duration, int passes, int threads)
{
    const auto sieveSize = sieve.size();

    if (showResults)
        printf("2, ");

    int count = (sieveSize >= 2); // Starting count (2 is prime)
    for (int num = 3; num <= sieveSize; num += 2)
    {
        if (sieve.contains(num))
        {
            if (showResults)
                printf("%d, ", num);
            count++;
        }
    }

    if (showResults)
        printf("\n");

    printf("Passes: %d, Time: %lf, Avg: %lf, Limit: %llu, Count1: %d, Count2: %d, Valid: %d\n",
           passes,
           duration,
           duration / passes,
           sieveSize,
           count,
           countPrimes(sieve),
           validateResults(sieve));

    printf("\n");
    printf("flo80_constexpr;%d;%f;%d;algorithm=base,faithful=no,bits=1\n", passes, duration, threads);
}

void run(uint64_t upperLimit, const Sieve &checkSieve, int numberOfThreads = 1, int runtimeSeconds = 5)
{

    unsigned int passes = 0;

    printf("Computing primes to %llu on %d thread%s for %d second%s.\n", upperLimit,
           numberOfThreads,
           numberOfThreads == 1 ? "" : "s",
           runtimeSeconds,
           runtimeSeconds == 1 ? "" : "s");

    const auto tStart = steady_clock::now();
    while (duration_cast<seconds>(steady_clock::now() - tStart).count() < runtimeSeconds)
    {
        vector<thread> threadPool;

        for (unsigned int i = 0; i < numberOfThreads; i++)
        {
            threadPool.push_back(thread([upperLimit]
                                        {
                                            auto sieve = Sieve(upperLimit);
                                            sieve.runSieve();
                                        }));
        }
        for (auto &th : threadPool)
            th.join();

        passes += numberOfThreads;
    }

    const auto tEnd = steady_clock::now();
    printResults(checkSieve, false, duration_cast<microseconds>(tEnd - tStart).count() / 1000000.0, passes, numberOfThreads);
}

int main(int argc, char **argv)
{
    uint64_t upperLimit = 1'000'000L;
    constexpr int runtimeSeconds = 5;

    if (argc > 1)
    {
        upperLimit = std::max((uint64_t)atoll(argv[argc - 1]), (uint64_t)1);
        assert(upperLimit < Sieve::maxSize);
    }

    auto checkSieve = Sieve(upperLimit);
    checkSieve.runSieve();
    const auto result = validateResults(checkSieve) ? checkSieve.count() : 0;

    const auto numberOfThreads = thread::hardware_concurrency();
    thread::hardware_concurrency();
    run(upperLimit, checkSieve, numberOfThreads, runtimeSeconds);
    run(upperLimit, checkSieve, 1, runtimeSeconds);

    return result;
}



Regards,
	Ryan Joseph



More information about the fpc-pascal mailing list