Conference PaperPDF Available

BIG INTEGER DATA TYPES — USAGE AND PERFORMANCE COMPARISON

Authors:
  • University North Croatia
  • University North, Croatia, University Center Varazdin

Abstract

Students in STEM fields often need to propose and develop programming solutions of different levels of complexity, for various scientific, technical, and engineering problems. In order to solve such tasks, they must have sufficient general programming skills and the knowledge of some standard programming language, such as C/C++, C#, Python, Java, Kotlin, JavaScript, Pascal. Alternatively, specialized programming languages and computing tools such as Matlab, Scilab, or GNU Octave, may be better suited for solving some of the problems and could sometimes be considered as a first choice. In this paper, the authors discuss the use of the nonstandard integer data types, so-called big integers, being able to store and handle large integer values that can be only represented with more than 64 bits. They analyse the possibilities of using those data types in education and programming practice for the well-known general-purpose languages: C/C++, C#, Java, JavaScript, Kotlin, and Pascal, as well as for the specialized high-level programming tools like free Matlab alternatives-Scilab and GNU Octave. For the languages without direct support for the big integers, the authors examine the possibility of inclusion of the freely available libraries, which include such types. After that, they measure and analyse the performance of the calculations with the big integer types on the standard Windows based, computing platform by using the fast-growing benchmark functions, such as factorials. The obtained results are presented, discussed, and compared.
BIG INTEGER DATA TYPES USAGE AND PERFORMANCE
COMPARISON
M. Mikac, R. Logožar, M. Horvatić, E. Dumić
University North (CROATIA)
Abstract
Students in STEM fields often need to propose and develop programming solutions of different levels of
complexity, for various scientific, technical, and engineering problems. In order to solve such tasks, they
must have sufficient general programming skills and the knowledge of some standard programming
language, such as C/C++, C#, Python, Java, Kotlin, JavaScript, Pascal. Alternatively, specialized
programming languages and computing tools such as Matlab, Scilab, or GNU Octave, may be better
suited for solving some of the problems and could sometimes be considered as a first choice.
In this paper, the authors discuss the use of the nonstandard integer data types, so-called big integers,
being able to store and handle large integer values that can be only represented with more than 64 bits.
They analyse the possibilities of using those data types in education and programming practice for the
well-known general-purpose languages: C/C++, C#, Java, JavaScript, Kotlin, and Pascal, as well as for
the specialized high-level programming tools like free Matlab alternatives - Scilab and GNU Octave. For
the languages without direct support for the big integers, the authors examine the possibility of inclusion
of the freely available libraries, which include such types. After that, they measure and analyse the
performance of the calculations with the big integer types on the standard Windows based, computing
platform by using the fast-growing benchmark functions, such as factorials. The obtained results are
presented, discussed, and compared.
Keywords: big integer, programming, performance comparison, benchmark, complexity, JavaScript,
C/C++, C#, Python, Kotlin, Java, Scilab, Pascal, Delphi, factorial, source code.
1 INTRODUCTION
Students in the STEM fields often need to develop programming solutions of different levels of
complexity for various scientific, technical, and engineering problems. In order to solve such tasks, they
must have sufficient general programming skills and the knowledge of some standard programming
language, such as C/C++, C#, Python, Pascal, Kotlin, Java, JavaScript. Alternatively, the specialized
programming languages and computing tools such as Matlab, Scilab, or GNU Octave, may be better
suited for solving some of the problems.
While trying to provide a wider perspective of our programming classes and relate them to other
technically oriented courses, such as digital electronics or computer architecture, the implementation of
the basic numerical calculations is one of the main tasks and topics. On the other hand, when teaching
the programming variables and data types, the latter are often covered only lightly, and without proper
elaboration. Many programmers in the high-level programming languages are used to the ready-made
solutions and are not very interested in the true mechanisms behind the coding and storing of the data
types they use, or the in the ways the calculations are performed with them. However, when confronted
with some special programming tasks or just the school extreme examples requiring either huge size of
integer types or the extra demands for the precision of the floating-point types, one may start
investigating the possibilities of the use of the nonstandard data types in the language(s) she or he uses.
The authors of this paper took that challenge, too and investigated the implementations of the big integer
types in several programming languages. A critically inclined reader might ask what would be the
purpose of such extreme calculations, and isn’t it just a computational l'art pour l'art. However, besides
the ever-growing inflations of all kinds, the examples from combinatorics or simply the need for the large
and fully precise fixed-point calculations justify such numerical investigations.
Large integer numbers that cannot fit in standard 32 or 64-bit integers supported in all general-purpose
programming languages are something that is required in certain type of calculations. Some of the
simplest examples presented to our STEM undergraduate students, such as factorial calculation, were
identified as ideal candidates for discussion about the usage of special data type enabling arithmetic
Proceedings of EDULEARN22 Conference
4th-6th July 2022, Palma, Mallorca, Spain
ISBN: 978-84-09-42484-9
2851
for, often-called, big numbers or big integers. Essentially, it is about data types or structures that should
allow arbitrary range, precision and bit-length to store extremely large numbers.
After this introduction, the paper starts with important section explaining the topic of the big-integer
support in the collection of the today widely known and popular general-purpose programming
languages, both the compiled and interpreted ones. All programming languages that are later used to
implement performance test programs are listed, including the information about native or extension-
based support for integer numbers of arbitrary range. Next section deals with the methodology of our
investigations, setting the calculation of the factorials as our benchmark. It gives all source codes used
for the benchmarks. After that, the results section presents and visualizes our measurements and
comments our findings. Conclusions and some remarks about possible future work related with this
subject are given in last section.
2 THE BIG INTEGER SUPPORT IN ANALYZED PROGRAMMING LANGUAGES
This paper is focused on analyzing the support for integer calculations with large values as large
values we consider integers not being able to store their values in standard 32-bit or 64-bit binary
memory words. Usually, that kind of integer numbers are called big integers or arbitrary range integers.
For that kind of “big numbers”, it is expected that there is no practical limit to their range or precision
except the limits implied by available memory. Of course, for integers we mainly discuss their range,
while the precision is considered to be able to provide usage of any successive integers in given range.
In order to document the abilities of general-purpose languages and specialized programming tools,
certain official documents had to be analyzed. Additionally, for languages not supporting big integers by
default, natively, the way of using additional libraries, if any, had to be investigated and documented.
Being involved with high-education process in STEM fields, the authors have some experience with
different kind of programming related courses but also with applying the programmer’s skills when
solving some real-world problems. During some previous studies, we noticed that we never analyzed
the support for big integers in programming languages we teach our students. One simple mathematical
definition resulting in fast-growing numeric function, calculating a factorial lead us to the problem of
correctly calculate factorials some of the detected issues and ways to solve it were described in [1]. In
addition to calculation issues, this paper not only expands the list of programming languages checked
and used, but it adds performance measurement in order to somehow value the quality of implemented
big integers support in different languages.
2.1 General purpose programming languages
General-purpose languages covered in this paper include, alphabetically ordered: C/C++, C#, Java,
JavaScript, Kotlin, Pascal, and Python. The languages were selected based on our educational
experience (C/C++, JavaScript, Kotlin, and Python are used in standard education process on our
institution), personal preference and history of use (C#, Pascal, Java), as well as the language popularity
popularity lists maintained by TIOBE [2] or PYPL [3] list most of those (except Pascal as first authors
historical favourite choice, due his Delphi experience) at top of others. Certainly, other languages could
be analysed and discussed, but we decided to limit on selected and not expand the scope of the paper.
2.2 Specialized high-level programming tools
Similar to general-purpose languages, in our education process we encourage students to use
specialized tools and programming languages included with them recently, we were evaluating free
Matlab alternatives Scilab and GNU Octave, mainly comparing their performance (as interpreted
environments) [4] and ability to provide quite good calculation performance when using suggested
vectorization approach [5]. So, it seemed natural for us to include big integer analysis for Scilab or GNU
Octave in this paper. Unfortunately, as it shall be seen in following sections, only limited usage of big
integers was successfully accomplished in Scilab, with poor performance results.
2.3 Integer numbers and their binary representation
The paper focuses on integer numbers floating-point numbers are not considered. It is well-known fact
that integer number binary representation is quite straightforward - the most important information
related to their binary representation is the number of bits used to store the number.
2852
Integers are binary represented as sets of bits of certain (predefined, by data type) length. Bit-length
directly relates to the value range. For x bits being used, it is clear that there are
2!
possible combination
of bits (varying from 0(10)all zeros - to
2! 1
(10)all ones for example, a standard 8-bit word can
store all combinations from 00000000(2) =0(10) to 11111111(2) =
2" 1
= 255(10). The programming
languages use different types of integers, but in general all languages support up to 64-bit integers.
In order to binary define certain positive integer number n, as described in [1], certain number of bits,
NoBD (Number of Binary Digits) must be used. The mathematics behind it, show that number of binary
digits can be calculated using the logarithmic function as:
NoBD(𝑛) =,
log#𝑛
+ 1
Similar, NoDD (Number of Decimal Digits) can be calculated as:
NoDD(𝑛) =,
log 𝑛
+ 1
For all integers that require NoBD larger than 64 bits, the representation and arithmetic limitations may
appear in certain languages not supporting integers of arbitrary bit-length.
2.4 Programming languages comparison
The programming languages selected for analysis in this paper differ significantly. We could compare
or group them using different criteria the way of code execution (compiled vs. interpreted, with
additional remarks about languages that may use intermediate code, being translated or “interpreted”
prior execution on target machine), the way of declaring variables (typed vs. untyped languages, or more
precisely strongly or static typed where the programmer has to explicitly define variable data type prior
execution against dynamical typed where the data type is determined during runtime), etc.
Table 1. Native big-integer support in analysed programming languages
Language
Native Support
Keyword / class / type
External Library
Keyword / class / type
C/C++
MPIR Multiple precision integers [7]
C data type mpz_t
C#
System.Numerics - BigInteger
Delphi
Delphi BigNumbers [8]
uses BigIntegers + BigInteger type
Java
import java.math.BigInteger
JavaScript
BigInt()
Kotlin
import java.math.BigInteger
Kotlin/Native
Pascal
TForge [9], [10]
FNXMultiprecission numbers [11]
GMP for FreePascal [12]
Python
import math + standard variable
Scilab
BigInteger toolbox [13]
bigint type
GNU Octave
Out of all analysed programming languages, only C/C++ and Pascal can be considered compiled
languages with no doubt. Both can be compiled and linked to executable code. Java uses intermediate
code when compiled, and uses virtual machine (JVM) to execute the code therefore it is somewhere
“in the middle”, when discussing execution and compilation. Kotlin, as “simpler Java”, also relies on Java
and JVM, but there are some additional “compilers” or translators including native compiler to executable
code (so called, Kotlin Native [6]), allowing the execution without virtual machine. Another popular
language, C#, compiles to intermediate byte-code and uses .NET environment at runtime.
2853
The compilation and execution status of other general-purpose languages is not so clear generally,
JavaScript and Python were always considered interpreted languages, but lately there were some
concept changes and optimized approach allow just-in-time (JIT) compilation or other similar techniques
that may significantly improve execution performance.
When considering variable declaration as a criterion C/C++, C#, Pascal, Java, Kotlin are considered
statically typed languages, while JavaScript and Python do not require variable type to be defined in
code they are considered dynamically typed languages.
The most important information for this article was whether certain language natively supports working
with arbitrary range integers. The Table 1 shows native big-integer support in analysed languages. For
languages not supporting big-integers natively, reference to available libraries is given.
For Pascal, only TForge library was used in our tests, other two solutions are just documented. As seen
in the table, there are two languages with no native support for big-integer type for which we were not
able to find any external libraries or other solutions that may allow big integer calculations Kotlin/Native
and GNU Octave. We would appreciate our readers having related information to get in touch with us.
For all other languages, we managed to execute performance tests.
3 METHODOLOGY
To make things as simple as possible, we decided to create simple test programs for each of analyzed
programming languages and measure the time required to execute the program with certain parameters.
Our intention was to determine and compare performances by measuring average time (duration) of
process of generating a list of factorials. The factorial calculation function was intentionally selected as
fast-grow function - as explained in [1], factorial for number as low as 21 results with integer value not
being able to fit 64-bit memory words. In other words, mathematically, for calculating factorial for
numbers n > 20, arbitrary range big integers must be applied in order to get valid results.
Table 2. Exact factorial calculation results for test numbers n above 20,
with number of binary digits (NoBD) and number of decimal digits (NoDD)
Factorial n!
NoBD
NoDD
2.432.902.008.176.640.000
62
19
51.090.942.171.709.440.000
66
20
1.124.000.727.777.607.680.000
70
22
25.852.016.738.884.976.640.000
75
23
620.448.401.733.239.439.360.000
80
24
15.511.210.043.330.985.984.000.000
84
26
403.291.461.126.605.635.584.000.000
89
27
265.252.859.812.191.058.636.308.480.000.000
108
33
8.683.317.618.811.886.495.518.194.401.280.000.000
123
37
295.232.799.039.604.140.847.618.609.643.520.000.000
128
39
10.333.147.966.386.144.929.666.651.337.523.200.000.000
133
41
815.915.283.247.897.734.345.611.269.596.115.894.272.000.000.000
160
48
119.622.220.865.480.194.561.963.161.495.657.715.064.383.733.760.000.000.000
187
57
30.414.093.201.713.378.043.612.608.166.064.768.844.377.641.568.960.512.000.000.000.000
215
65
Exact factorial calculation results for certain relatively low numbers n is given in table 2. In addition to
factorial value, two informative columns are included one showing NoBD (number of binary digits), as
described in 2.3, and other showing number of decimal digits (NoDD). It can be seen that 128-bit length
is reached for n = 34. For all test programs, the exact list was used to manually check validity of obtained
results. All the test programs, for all languages managed to get correct values!
The test programs were implemented so that the execution depends on three parameters Nfrom and
Nto were used as first and last number for which the factorial was calculated, and Nrep as parameter
defining number of repeated procedures. For instance, with Nfrom = 1, Nto = 1000 and Nrep = 50, the
2854
program repeated generation of all factorials for numbers in interval from 1 to 1000 for 50 times. In order
to measure the performance, total time was measured and finally divided with Nrep to get average time
required to generate list of factorials. For each number N, complete factorial calculation is executed
(complete loop multiplying all numbers from 1 to N) therefore, our performance tests dominantly
benchmark big integer multiplication.
Since the scenario of calculating all the factorials for such a large and continuous range/interval cannot
be considered realistic, we intentionally skipped possible performance improvement when calculating
1000!, we could determine all other factorials from 1 to 999! using single pass through for-loop, but
instead we decided for brute-force test repeating the calculation for each number in [Nfrom, Nto] range.
In order to measure the time required to perform complete calculation process, proper time
measurement functions had to be used. Since all the languages used for our performance comparison
offer different functions to check current time (with different precision), we had to check documentation
and adapt to each any every language.
3.1 Development tools
Modern development environments are often available for free (such as Community editions of
professional tools like Microsoft Visual Studio or Intellij IDEA, or completely free such as Microsoft Visual
Studio Code, Lazarus) and offer support for multiple languages. Using more programming languages
lead us to using more development tools, probably with some redundancy and overhead. When working
on this paper, following development environments were used Visual Studio 2022 Community edition
to work with C/C++ and C#; Visual Studio Code to work with JavaScript, Python and Java, Intellij IDEA
to work with Java and Kotlin, Delphi (commercial) for Delphi and Lazarus for Free Pascal. In order to
simplify installation of certain extensions and tools, package manager for Visual Studio, vcpkg [14] was
used. Visual Studio Code was extended with several standard add-ons that allowed easier setup for
using VS.Code for Python and Java.
3.2 Time measurement
All languages offer certain functions to get current time. Some of the languages offer more specialized
functions. The simplest approach, supported in most languages, was to get time (in number of
milliseconds) past from certain fixed timestamp often, Januray 1st, 1970, as historically used in most
languages - prior starting calculations and repeat the same thing after the calculations finish. Difference
between two obtained values represent number of milliseconds (or other timer accuracy unit, depending
on precision of integrated functions) required to finish the calculations. Of course, there may be internal
differences in implementation of the functions, but that is something we did not analyzed. List of functions
used, for each language, is given in table 3. Exact examples of usage are completely given in source
codes in next subsection.
Table 3. Time measurement functions used in performance test programs
Language
Functions
C/C++
std::chrono::high_resolution_clock::now() + std::chrono:duration
C#
System.Diagnostics + StopWatch()
Delphi
getTickCount()
Java
System.currentTimeMillis()
JavaScript
performance.now()
Kotlin
System.currentTimeMillis()
Pascal
getTickCount()
Python
import time + time.time()
Scilab
tic() toc()
3.3 Source code
This subsection includes source-code of our test programs in all analyzed languages. By that, anyone
can reimplement the same and check the performance on its own computer.
2855
The source code is given without any additional explanation.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>
#include <chrono>
#include "mpir.h"
using namespace std;
using namespace std::chrono;
void main()
{
int Nrep = 50, Nfrom = 1, Nto = 1000;
mpz_t tmpFct; mpz_init(tmpFct);
mpz_t tmpN; mpz_init(tmpN);
auto t1 = high_resolution_clock::now();
for (int t = 1; t <= Nrep; t++)
{ for (int N = Nfrom; N <= Nto; N++)
{ mpz_set_d(tmpFct, 1);
for (int i = 1; i <= N; i++)
{ mpz_set_d(tmpN, i);
mpz_mul(tmpFct, tmpFct, tmpN);
}
}
}
auto t2 = high_resolution_clock::now();
auto delta = t2 - t1;
duration<long long, nano> duration(delta);
double deltaMS = delta.count() / 1000000;
double avgT = deltaMS / Nrep;
cout << "Avg. = " << avgT << "ms" << endl;
}
using System.Numerics;
using System.Diagnostics;
int Nrep = 50, Nfrom = 1, Nto = 1000;
BigInteger tmpFct = new BigInteger(1);
Stopwatch duration = new Stopwatch();
duration.Start();
for (int t = 1; t <= Nrep; t++)
{ for (int N = Nfrom; N <= Nto; N++)
{ tmpFct = (BigInteger)1;
for (int i = 1; i <= N; i++)
{
tmpFct = tmpFct * i;
}
}
}
duration.Stop();
long deltaMS = duration.ElapsedMilliseconds;
float avgT = (float)deltaMS / Nrep;
Console.WriteLine("Avg.duration =" + avgT + "ms");
C/C++ with MPIR library
C#
Figure 1. C/C++ and C# source code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Nrep = 50;
Nfrom = 1; Nto = 1000;
t1 = performance.now();
for (t = 1; t <= Nrep; t++)
{ for (N = Nfrom; N <= Nto; N++)
{ tmpFct = BigInt(1);
for (i = 1; i <= N; i++)
{ tmpFct = tmpFct * BigInt(i);
}
}
}
t2 = performance.now();
avgT = (t2-t1) / Nrep;
console.log("Avg.duration = " + avgT);
import math
import time
Nrep = 50
Nfrom = 1
Nto = 1000
t1 = time.time()
for t in range(1,Nrep):
for N in range(Nfrom,Nto+1):
tmpFct=1
for i in range(1,N+1):
tmpFct=tmpFct*i
t2 = time.time()
avgT = (t2-t1)*1000/Nrep
print("Avg.duration = " + str(avgT))
JavaScript
Python
Figure 2. JavaScript and Python source code
Please note that the factorial calculation is done inside for-loop with counter variable igiven source
does not include printouts of the factorial results (if needed, it should be done inside N-for-loop, after i-
for-loop). Also, note that the code is somehow “compressed”, meaning it is not completely visually well-
formed as we use it when coding some empty rows were skipped, some add, curly brackets and blocks
brought closer, some code rows were wrapped etc. Also, because figures include two sources each
next to another, we intentionally tried to sync the lines by functionality. But, overall, the code is correct
and can be reused in languages with no native big integers support, the environment has to be setup
properly in order to successfully execute the programs.
2856
For anyone with experience in programming with general-purpose languages, all the sources should be
easily analyzed and understood. The same variable names were used in all languages (not using any
particularly naming scheme). Shortly there were three loops in the code the first loop with counter t
is used to repeat calculation Nrep times, the second with counter N is used to pass through all numbers
for which factorial is calculated (from Nfrom to Nto), and the third loop is used to implement the simplest
possible (but unoptimized) calculation of the factorial, by multiplying all the values from 1 to N, using
counter i. The variable tmpFct is used to calculate factorials inside the third loop (results can be printed
for each required N at the end of the second loop).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import java.math.BigInteger;
public class FctJava2022 {
public static void main(String[] args) {
int Nrep = 50, Nfrom = 1, Nto = 1000;
BigInteger tmpFct;
BigInteger tmpI;
long t1 = System.currentTimeMillis();
for (int t = 1; t <= Nrep; t++)
{ for (int N = Nfrom; N <= Nto; N++)
{ tmpFct = BigInteger.valueOf(1);
for (int i = 1; i <= N; i++)
{ tmpI = BigInteger.valueof(i));
tmpFct = tmpFct.multiply(tmpI);
}
}
}
long t2 = System.currentTimeMillis();
float avgT = (t2-t1) / (float) Nrep;
System.out.println("Avg. = " +
Float.toString(avgT));
}
}
import java.math.BigInteger
fun main(args: Array<String>) {
val Nrep = 50
val Nfrom = 1; val Nto = 1000
var tmpFct: BigInteger
var tmpI: BigInteger
val t1 = System.currentTimeMillis()
for (t in 1..Nrep)
{ for (N in Nfrom..Nto)
{ tmpFct = BigInteger.valueOf(1)
for (i in 1..N)
{ tmpI = BigInteger.valueOf(i.toLong())
tmpFct = tmpFct.multiply(tmpI)
}
}
}
val t2 = System.currentTimeMillis()
val avgT = (t2 t1).toFloat() / Nrep
println(("Avg.duration = " + avgT.toString())
}
Java
Kotlin
Figure 3. Java and Kotlin source code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
program fctDelphi2022;
{$APPTYPE CONSOLE}
uses System.SysUtils, Windows,
Velthuis.BigIntegers;
var Nrep, Nfrom, Nto, t, N, i:integer;
t1, t2: DWORD;
tmpFct: BigInteger;
begin
Nrep := 50; Nfrom := 1; Nto := 1000;
t1 := getTickCount();
for t:=1 to Nrep do
begin
for N:=Nfrom to Nto do
begin
tmpFct := BigInteger(1);
for i:= 1 to N do
begin
tmpFct := tmpFct * i;
end;
end;
end;
t2 := getTickCount();
avgT := (t2-t1)/Nrep;
writeln('Avg.dur.='+floattostr(avgT)+'ms');
end.
program fctPascal2022x;
uses tfNumerics, Windows, Sysutils;
var Nrep, Nfrom, Nto, t, N, i:integer;
t1, t2: DWORD;
tmpFct: BigInteger;
begin
Nrep := 50; Nfrom := 1; Nto := 1000;
t1 := getTickCount();
for t:=1 to Nrep do
begin
for N:=Nfrom to Nto do
begin
tmpFct := BigInteger(1);
for i:= 1 to N do
begin
tmpFct := tmpFct * i;
end;
end;
end;
t2 := getTickCount();
avgT := (t2-t1)/Nrep;
writeln('Avg.duration='+floattostr(avgT)+'ms');
end.
Delphi + Velthuis.BigIntegers
FreePascal / Lazarus + TForge extension
Figure 4. Delphi and FreePascal/Lazarus source code
2857
3.4 The fastest program – C/C++ with MPIR and optimized factorial function
The fastest calculation and overall test results were obtained using the specific, highly optimized factorial
calculation function of MPIR library [7] used with C/C++ compiler. The same library was used for
standard unoptimized, loop-multiplication based calculation and also performed quite well (details on
performance test results are given in next section). The code using MPIR is depicted in Fig. 1, left
special big integer type is using keyword mpz_t and, according to official library documentation, specific
functions (mpz_init, mpz_set, mpz_mul) have to be used to work with that data type.
Among others, the function mpz_fac_ui, implemented as part of the library, can be used to calculate
the factorial of given number. Based on obtained results and available documentation, we can only
conclude that it is highly optimized and gives the best results in our tests. The way to use it is quite
simple in order to get the fastest results, the code in Fig. 1 left should be changed lines from 18 to
21 should be commented or deleted and replaced with simple call to the specialized function
mpz_fac_ui(tmpFct, N); - the first parameter is resulting variable and the second parameter is the
number for which the factorial has to be calculated!
4 RESULTS
All the measurements were made on standard Windows based PC (Windows 10 Pro, 64-bit) with Intel
i3-6100U CPU, 16GB RAM, NVM.e SSD disk drive. The results shown in table 4 were obtained by
executing the programs given in source code subsection in 3.3. Results from the table are visualized on
diagrams on Fig. 5 and Fig. 6.
Table 4. Performance test results average duration of execution in milliseconds – Nrep = 50
Language / environment
Nfrom = 1, Nto = 1000
Nfrom = 1, Nto = 250
C/C++ 32bit + MPIR
237.46
5.02
C/C++ 64bit + MPIR
96.18
2.53
C/C++ 32bit + MPIR fact
33.86
1.00
C/C++ 64bit + MPIR fact
9.28
0.53
C#
96.64
2.52
Delphi 64 bit
144.20
7.37
Delphi 32 bit
213.38
8.81
Java (VS.Code)
87.92
5.51
Java (IntelliJ IDEA)
98.73
7.81
JavaScript (Edge)
149.80
7.84
JavaScript (Chrome)
142.02
6.69
JavaScript (Firefox)
735.06
14.68
JavaScript (Opera)
145.00
7.64
Kotlin
97.37
7.25
Pascal + TForge
409.66
13.12
Python
288.38
11.08
For certain native development platforms (Visual C++, Delphi) both 32- and 64-bit executables were
built and tested. It can be seen that both C/C++ and Delphi perform significantly better when using 64-
bit compiler.
JavaScript was tested in four web browsers the results look quite strange for Mozilla Firefox browser
that seems to have much lower performance, when compared with others, especially in test with Nto =
1000, where it was almost 5 times slower than other browsers (nicely depicted in Fig. 5)!?
One, for authors little unexpected, conclusion may be that interpreted and dynamically typed languages
such as JavaScript and Python offer the performances comparable to other, even natively compiled
environments. The similar could be said for C#, Java and Kotlin being intermediately compiled, they
offer great performance it must be because well designed and optimized JVM and .NET runtime. For
us, standard old-school programmers, it was expected that native compiled C/C++ od Delphi (but,
2858
unfortunately, without native big integer support) may provide the fastest calculations, but we were
slightly disappointed seeing other, more modern, languages have similar or even better results. Luckily,
MPIR library used with C/C++ includes optimized factorial calculation function that beats all other
solutions.
Please note that Scilab was not listed in results table. That is due its poor performances as seen, the
slowest results were obtained using JavaScript in Firefox. But, even those results, for example, 735ms
for generating all the factorials for range [1, 1000] may be considered great result! Not to mention little
less than 15ms for calculating all the factorials in range [1, 250]! But, in Scilab the overall procedure
lasted so long that we decided to cancel the execution. Just to give some valuable information Scilab
uses additional BigInteger toolbox [13] and can work with big integer values. But, for instance,
calculating only one small list of factorials (simplest possible multiplication implementation, as in other
languages shown in source examples), for numbers in range [1, 50] it required more than 280 seconds!
Or, calculating single factorial, e.g. 100! lasts 180 seconds.
Figure 5. Chart visually presenting results for test with Nfrom = 1, Nto = 1000, time in milliseconds
Figure 6. Chart visually presenting results for test with Nfrom = 1, Nto = 250, time in milliseconds
96.64
237.46
96.18
33.86 9.28
213.38
144.20
98.73 87.92
142.02
149.80
735.06
144.99
97.37
409.66
288.38
0
100
200
300
400
500
600
700
800
Average execution time in milliseconds
Parameters
: N
rep
= 50, N
from
= 1, N
to
= 1000
ms
2.52
5.02
2.54
1.00
0.53
8.81
7.37
7.81
5.51
6.69
7.84
14.68
7.64
7.25
13.12
11.08
0
4
8
12
16
Average execution time in milliseconds
Parameters:
N
rep
= 50, N
from
= 1, N
to
= 1000
ms
2859
After conducting presented performance analysis, we shall express our regret on space limitations for
this paper, since some additional comments, explanations or even source code modifications may be
discussed. However, that could be marked as possible future work or a kind of extension of this paper.
5 CONCLUSIONS
The main objective of the paper was to analyze the abilities of the arbitrary range integers, so called big
integers, in the collection of the today widely known and popular general-purpose programming
languages, both the compiled and interpreted ones. We successfully managed to measure the big
integer calculation performances of different languages by implementing benchmark function based on
the fast-growing factorial function. Based on the obtained results, some objective findings were
presented. It was concluded that most modern and lately popular languages such as JavaScript, Python,
C# or Java natively support the arbitrary large integer arithmetic and that they all perform quite well,
even above our conservative expectations. On the other hand, more classic languages, such as C/C++
and Pascal do not support big integers natively, so that they relay on external libraries. Fortunately, that
kind of libraries exists, they are usually freely available and perform very well.
In general, all of the most popular languages today provide well performing big integer calculation
abilities. However, there was a slightly disappointment related to the big integer support in specialized
mathematical tools such as Scilab and GNU Octave even though the type support may be available,
the performances we obtained were so poor that we were not even willing to compare it with the results
of general-purpose languages.
REFERENCES
[1] M. Mikac, M. Horvatić, “On explaining variable range in standard programming languages (to
STEM students)”, in ICERI2019 Proceedings, IATED Academy, pp. 1551-1561, 2019.
[2] TIOBE Index April 2022. Accessed 06. May 2022. Retrieved from https://www.tiobe.com/tiobe-
index
[3] PLPY Popularity of Programming Language. Accessed 06. May 2022. Retrieved from
https://pypl.github.io/PYPL.html
[4] M. Mikac, M. Horvatić, Using open-source numerical computation software in education basic
performance comparison and lab examples”, in EDULEARN20 Proceedings, IATED Academy,
pp. 2319-2327, 2020.
[5] M. Mikac, M. Horvatić, V. Mikac, “Using vectorized calculations in Scilab to improve performances
of interpreted environment”, in INTED2020 Proceedings, IATED Academy, pp. 2127-2136, 2020.
[6] Kotlin Native. Accessed 08. May 2022. Retrieved from https://kotlinlang.org/docs/native-
overview.html
[7] B. Gladman, W. Hart, J. Moxham, et al. MPIR: Multiple Precision Integers and Rationals, 2015.
version 2.7.0, A fork of the GNU MP package (T. Granlund et al.). Accessed 10. May 2022.
Retrieved from https://mpir.org
[8] R. Velthuis. Delphi Big Numbers. Accessed 10. May 2022. Retrieved from
https://github.com/rvelthuis/DelphiBigNumbers
[9] TForge for Lazarus. Accessed 10. May 2022. Retrieved from
https://sergworks.wordpress.com/2016/04/10/tforge-0-75/
[10] TForge download. Accessed 10. May 2022. Retrieved from
https://torry.net/files/vcl/security/strong/tforge073.zip
[11] M. Martin. FNX Multiprecission numbers library for FreePascal on Linux. Accessed 10. May
2022. Retrieved from http://www.ellipsa.eu/public/fnx/fnx.html
[12] GMP for FreePascal. Accessed 10. May 2022. Retrieved from https://wiki.freepascal.org/gmp
[13] D. Clement, P. Roux. BigInteger toolbox for Scilab. Accessed 10. May 2022. Retrieved from
https://forge.scilab.org/index.php/p/bigint/
[14] VCPKG package manager. Accessed 10. May 2022. Retrieved from https://vcpkg.io
2860
ResearchGate has not been able to resolve any citations for this publication.
MPIR: Multiple Precision Integers and Rationals
  • B Gladman
  • W Hart
  • J Moxham
B. Gladman, W. Hart, J. Moxham, et al. MPIR: Multiple Precision Integers and Rationals, 2015. version 2.7.0, A fork of the GNU MP package (T. Granlund et al.). Accessed 10. May 2022. Retrieved from https://mpir.org
Delphi Big Numbers. Accessed 10
  • R Velthuis
R. Velthuis. Delphi Big Numbers. Accessed 10. May 2022. Retrieved from https://github.com/rvelthuis/DelphiBigNumbers
FNX -Multiprecission numbers library for FreePascal on Linux
  • M Martin
M. Martin. FNX -Multiprecission numbers library for FreePascal on Linux. Accessed 10. May 2022. Retrieved from http://www.ellipsa.eu/public/fnx/fnx.html
BigInteger toolbox for Scilab. Accessed 10
  • D Clement
  • P Roux
D. Clement, P. Roux. BigInteger toolbox for Scilab. Accessed 10. May 2022. Retrieved from https://forge.scilab.org/index.php/p/bigint/