Abstract
We review the dimensional check problem of the high-level programming languages, discuss the existing solutions, and come up with a new solution suited for scientific and engineering computations. Then, we introduce Univec, our C++ library designed to make scalar, vector, and matrix operations using units of measurement. Moreover, Univec supports dimensional-aware operations for complex numbers, quaternions, octonions, and sedenions. We provide tables of the relevant functions and operators implemented. Our library was compared with several existing solutions, and the results are shown in the performance section. Finally, we present our future plans for improving the current implementation.
Similar content being viewed by others
Introduction
Dimensional analysis is one of the most powerful tools available in physics to verify the correctness of mathematical formulas describing physical processes. However, this tool alone is not able to spot all possible mistakes. It allows only a fast check, highlights faulty operations, and provides a consistent examination of the whole process.
Nowadays, complex simulations and derivations are performed using computing algorithms taking advantage of high-speed calculation and numerical correctness due to the advances in computing technology. However, when using complex algorithms spanning thousands of source code lines divided into tens of files, we tend not to automatically trust the results or, much worse, accept them blindly. Moreover, because there is no bug-free software implementation, we have to mitigate the impact of possible errors using countless checks in code and proper testing procedures, which are often as time-consuming as the development itself.
Therefore, an appropriate approach is to use techniques that could help reduce the overall cost of software development1. Unfortunately, due to historical reasons, most high-level programming languages lack a dimensional check as a language feature; they work on floats and integers, leaving to the programmer’s judgement the responsibility to keep track of their semantic meaning, leading to many potential mistakes.
Several libraries provide dimensional analysis check at compile time or at run-time. However, as shown by McKeever2, there is an evident reticence to adopt such solutions due to the following reasons:
-
Difficulty in using unfamiliar and complex libraries
-
Fear of adding external dependencies
-
Concerns about the performance impact
-
Possible limitations on using external libraries or complex data structures such as matrices and vectors.
In “Existing solutions”, we review the existing solutions available in the most common programming languages. We describe our proposed solution and present concrete examples in “Our implementation”. In “Unit testing”, we discuss the testing approach, and in “Performance study”, we provide a performance analysis. Limitations of the current development, along with plans for improvements are addressed in “Limitations and future plans”, and conclusions are drawn in “Conclusions”.
Existing solutions
A comprehensive review of several existing solutions for dimensional analysis in programming languages can be found in Preussner’s work3. Apple’s Swift4 and F#5 are two widespread programming languages that provide native support for UoM-aware (units of measure) quantities. Promoting UoM analysis to a language feature has the benefit of immediate access to meaningful error messages. Unfortunately, only a few programming languages offer native support for this important topic. Instead, most languages have an external library that relies on generic programming techniques.
The most popular solution for C++ is Boost.Units6, which makes possible the UoM validation at compile time. Its main advantage is that it is included in the Boost framework, a comprehensive set of libraries that are used as a launchpad for features that are later included in the language’s standard library. Unfortunately, Boost is quite often seen as a heavy dependency. For the FORTRAN language there is the PHYSUNITS module7 which provides support for dimensional-aware routine creation. While this solution is versatile, allowing working with both F77 and F90 code, because the dimension information is carried alongside numerical values, PHYSUNITS introduces a run-time execution overhead in terms of speed and memory usage. Dimensional analysis is not limited to compiled languages, Python supports run-time dimensional analysis checks thanks to libraries like Pint8.
Almost all existing libraries do not provide native support for vectorial computation. However, for vectorial operations in high-energy physics there are two solutions: CLHEP9 and Eigen10. They provide representations for both 2D and 3D vectorial quantities and n-dimensional matrices, but none of them has built-in support for dimensional-aware units, relying only on primitive numeric types available in C++.
We have to mention that our approach is not the first attempt to solve this specific issue. For example, the CORSIKA 8 simulation tool11, a C++ rewrite of CORSIKA12, uses a similar solution to address the same problem of combining unit systems with vector arithmetic. The approach adopted there was to combine Eigen v310 with the PhysUnits library13, allowing them to perform dimensional-aware vector arithmetic without any performance penalty11.
Our implementation
To improve the accuracy and lower the run-time overhead of the scientific and engineering computations, we developed Univec, our C++ library that allows scalar, vector, matrix, complex, quaternion, octonions, and sedenion operations integrating the Boost.Units6 library features.
We decided to implement a library that uses an existing UoM analysis library and wrap it in an easy-to-use interface for physicists. We rely on Boost::Units for dimensional checks, but we provide classes that can represent n-dimensional vectors and matrices. This way, we can provide dimensionally correct methods for common operations such as vector norms and products, matrix determinants and other operations. The performance of our solution is in line with Boost::Units, because one of our development objectives was not to add any perceptible runtime overhead and to make possible automatic optimizations by the compiler.
A summary of the functions and aliases available for vector and matrix types can be found in Tables 1, 2, 3, 4, 5, 6 and 7, while the complete source code, released under LGPLv3 license, can be found at the address https://gitlab.com/micrenda/univec.
All the methods implemented return a copy of the original vector. However, for methods for which the result is compatible with the calling class type, we created an in-place version of the method, which modifies the object instance. These methods start with the prefix do (e.g. doConj()) to be easily differentiated from the copy version of the same method. These methods are usually faster than those that copy data because they do not allocate additional memory for their operations.
Our implementation heavily uses generic template programming, shifting the cost of the dimensional check at compiling time and removing, in principle, any run-time overhead. However, the drawback is an increased usage complexity, which may discourage non-experienced C++ developers. We tried to mitigate this issue by providing custom descriptive error messages and a set of default quantity aliases covering the most common quantities used in physics. This approach allows easy-to-remember type names when defining a variable, such as:

which is a much shorter name than its canonical name:

.
We decided to keep the set of aliases in SI, GCS and Gauss units, isolated from the main library development and were published as a separated project, at the address https://gitlab.com/micrenda/qtydef.
Vector operations
Univec allows writing a compact and semantically clear code with dimensional-check at compile-time. This is done using a set of classes, shown in Table 5, representing different types of quantities, such as vectors and matrices. In our implementation we tried to prioritize clarity and performance, two objectives that are difficult to reconcile because fast code tends to be quite complex and difficult to read. We implemented all the n-dimensional Cartesian vector classes, including complex numbers and quaternions, in a single header-only class. This approach required heavy use of template programming. However, it provides two important benefits: code duplication was significantly reduced, and we got a highly optimized implementation because the method resolution is performed at compile-time since we do not have inheritance and virtual functions, allowing efficient compiler optimizations. Furthermore, the complexity of the code due to generic programming was mitigated using the last C++ keywords like requires, which improve substantially the code readability.
During the design, we realized that complex numbers, quaternions, octonions, and sedenions methods were a super-set of the methods available in Cartesian \(n-\)dimensional vectors (see Table 2). Therefore, we used the same classes for these entities, marking complex quantities as vectors with a negative dimensional number. In this way, we can represent complex numbers as VectorC<-2>, quaternions as VectorC<-4>, etc., enabling and disabling some methods using the N template parameter. However, for better readability, a set of alias for common entities is provided, as shown in Table 5. This solution allowed a high degree of code reuse and painless conversion between the entities without requiring inheritance and virtual method resolutions at runtime.
Matrix operations
During the development of the vectorial operations, we realized that matrix operations would be needed soon, which shall also benefit from the same UoM validation. The main difficulty was that not all operations were available for any matrices. For example, an operation like the determinant of a matrix is defined only for a square matrix. For this reason, we made heavy use of the C++ concept requires. Although this severely limits its usage only within projects that use at least C++20, it allows a clear definition of the function usage constraints, and produces meaningful error messages when these conditions are not met.
As a design decision, matrix dimensions can be set using integer templates, as shown in Table 5: this means that matrix dimension can not be changed at runtime, allowing non-negligible performance optimizations by the compiler. As we can observe in Tables 6, 7 and 8, we decided to limit the method’s implementations to the one which have a deterministic and non-iterative solution, omitting methods requiring matrices decomposition. In a future release, we may add support for this class of methods, allowing the calculation of eigenvalues, eigenvectors, matrix \(L_2\) norms and similar quantities.
Floating point limitations and tolerances
Representation of floating-point number is a tricky point in any software package that handle non-integer quantities. The IEEE Standard for Floating-Point Arithmetic (IEEE 754)14, is the de facto standard in modern computers, and C++ supports it using the float and double variable types. This format allows storing any number inside a fixed size mantissa and exponent, allowing the representation of up to \(1\,\times \,10^{308}\) or down to \(1\,\times \,10^{-308}\), with around 15-digits precision.
One first issue is that some rational numbers that are perfectly representable on a base-10 numeric system can not be expressed on a base-2 numeric system and inevitably introduce a rounding error.
Another issue is that trigonometric and transcendental functions in C++ are calculated using a series sum and are truncated after a specific precision is achieved. This is usually not a problem in the engineering and scientific fields because we are interested in the approximate values of our calculation, given that we do not fall into known floating-point pitfalls. However, our library is quite sensitive about this issue because often, we have to check if two vectors are parallel or perpendicular, or if a matrix is diagonal: these actions do require to check the result against the exact values, which is tricky when working with floating-point quantities.
To manage this last issue, we introduced the concept of tolerance, represented by the class Tolerance. This class can be passed as a template parameter to any function that requires comparing two values for equality (usually, but not always, the methods starting with the “is” prefix). We provide a default implementation which compares two values as equals if they equal to the 10th decimal digit. While this approach is not quite robust, it has the advantage of being relatively fast and easy to understand. If a different approach is required, the user can provide a custom class for all the methods or just for some specific calls.
Frame transformations
While we were using Univec we found that some formulas become much simpler when we use specific coordinates transformation. One good example comes from the simulation of microscopic electron-molecule non-relativistic interactions in the center-of-momentum reference frame. A transformation-matrix can represent any linear transformation: complex transformations can be easily represented and computed by chaining multiple simpler transformations such as translations, rotations, and scaling operations.
One can make a frame transformation using a concrete implementation of the abstract class BaseFrameC3D (in Table 4, we present ready-to-use implementations).
A vector can be easily transformed into a new reference frame:

Multiple transformations can be combined to describe complex scenarios using the syntax:

Vector conversion
Another valuable feature of Univec is changing the coordinate system of a vector. The conversion from a type to another is made via a constructor, which is explicit when the conversion is computationally expensive (e.g. VectorP2D to VectorC<2>), and implicit otherwise (e.g. VectorC<4> to Quaternion).
These methods can be useful for executing operations on vectors represented in different coordinate systems. For example, for converting a VectorP2D into a VectorC2D, we can use the following code:

while for 3D vectors, we can use:

and for complex and quaternions, we have:

Usage examples
In this subsection, we will present two realistic examples of using Univec. For the first example we will show a simple implementation of the Bethe–Bloch equation, a handy formula for evaluating the energy deposit of ionizing charged particles. For the second example we will show how our library can be used in elementary particle physics, evaluating the decay rate of the \(W^-\) boson. It is important to notice that we perform the calculation using SI units and not the natural units that are normally used. This is because there is currently no support for natural units in Boost::Units, but we plan to address this issue in the near future (see “Limitations and future plans”). All the examples presented in this article are available in a public repository15.
Bethe–Bloch
The well-known Bethe–Bloch formula16,17,18 is used to calculate the mean energy loss of a charged particle. For example, if we have a particle with velocity v, charge z (in a unit of elementary charges), traveling a medium with electron number density n and mean excitation energy I, we can calculate the mean energy-loss using the formula:
where \(m_e\) is the electron rest mass, c is the speed of light and \(\beta =v/c\) as well as \(\gamma =1 / \sqrt{1 - \beta ^2}\) are the Lorentz factors.
Using Univec, we can encode this formula into a compact expression, enjoying a fully dimensional analysis validation:

\(W^- \rightarrow e^- + {\bar{\nu }}_e\) decay
The previous example was helpful for presenting the dimensional analysis validation, but the equation itself only contained scalar operation. We will show here how vector, spinor, and matrix operations can be combined in a compact syntax to perform advanced calculations. In this example we reproduce a derivation from19, ch. 15 which describes the properties of the W and Z bosons. To calculate the decay rate of a \(W^-\) boson into an electron, \(e^-\), and an electronic anti-neutrino, \({\overline{\nu }}_e\) (shown in Fig. 1), we calculate the decay matrix elements using
where \(\gamma ^\mu \) are the \(\gamma \)-matrices in Dirac–Pauli representation and \(\epsilon _{\mu }^\lambda \) represents the three possible polarization states
and \(v\left( p_4\right) \), \({\bar{u}}(p_3)\) are, respectively, the adjoint particle spinor and antiparticle spinor, defined as
with \(N=\sqrt{E + m}\). Finally, having \({\mathcal {M}}_{f i}\), we can calculate the average decay rate using
and
where \(p*\) is the momentum of the final particle in the center-of-mass frame.
Lowest-order Feynman diagram for \(W^-\) boson decay into an electron and an anti-neutrino19.
The equations above are dimensional-invalid in SI units (e.g., we sum a mass and energy). However, in natural units, we define quantities like mass, momentum, length, etc., in equivalent energy units, so their operations are legit. Unfortunately, our current implementation does not support natural units, yet, so we are forced to convert to SI units to perform this calculation. The result is the code below, which uses our custom classes for matrices, vectors, and complex values to produce a compact and readable code with a full dimensional check at compile time:


As we have already explained, using SI units is not a natural choice for HEP physicists. Due to the nature of the subject, we have to handle SI units values that differ from each other by many orders of magnitude. Due to this fact, a substantial precision loss can occur during calculations (see “Limitations and future plans” for details). However, our example presented above produced pretty good results, near to the accepted value of \(\tau \approx O(10^{-25}s)\).
Methods
An effective software library needs an efficient and reliable procedure for validating both the functionality, the correctness, and the performances obtained. Therefore, in implementing this library, we perform two type of tests: a test of the functionality and correctness of the implemented methods and a test of performance compared with similar techniques for calculating the same operation.
When we talk about the functionality and performance tests, even though the source code of this library was carefully written, we felt the need to add an additional layer of verification by integrating a testing system.
To deliver a reliable application, we have defined a good software development practice by incorporating a Test-Driven Development (TDD) system. More details about this integration are presented in “Unit testing”. Additionally, we chose to use two different compilers, GCC20 and Clang21, to support the wide range of machines our software could run on. The amount of code executed during our tests is greater than 95% (according to gcovr22—the code coverage utility we use), ensuring good code coverage.
Unit testing
Univec was developed using the Test-Driven Development (TDD) software design paradigm where code development and testing occur simultaneously. By integrating a unit testing strategy, we can separately test for the correctness of our application’s functionality. To implement these tests, Univec uses GoogleTest23, one of the most popular C++ unit testing frameworks. For each implemented method and operator of our code an associated test ensures that the expected behavior satisfies our specifications and that functionality is preserved.
We have chosen to integrate CI/CD, another modern software development practice, through automated integration of testing and code documentation into the stages of the software development. We use GitLab24 to host our repository, allowing us to access the provided CI/CD feature. For each commit or push GitLab triggers the build of code, runs all unit tests implemented with GoogleTest and extracts the annotated C++ files to generate the online Univec documentation using Doxygen25. Furthermore, at the end of each test procedure on the pipeline, several report files are generated: two files with the test results (one for each compiler: junit_gcc.xml and junit_clang.xml) and one file that briefly presents code coverage results for the tests run (coverage_gcc.xml).
This combined approach, CI/CD and unit tests, assures us of the Univec’s functionality and maintainability.
Performance study
Performance comparison against existing solutions is a crucial aspect in the introduction of a new library. We compare Univec methods against four different approaches of performing the same operations:
-
Raw: using only primitive C++ types such as double.
-
Semi: using Boost::Units6 types and methods.
-
BLAS26/LAPACK27: using OpenBLAS28 and LAPACKE29 (for Linux) or the Accelerate framework30 (for macOS) methods over primitive C++ types such as double.
When the operation is too complex to implement (e.g. determinant of \(N \times N\) matrix, where N>4 for Raw and Semi approaches) or unavailable in a given library (e.g. cofactors of a \(3 \times 3\) matrix for BLAS approach), the result is omitted. We compare a subset of operations, as shown in Figs. 2 and 3. The procedure of performance testing is performed using this scheme:
-
1.
Input data are generated for Raw operation, using \(n \cdot 10000\) random values between − 1000 and 1000, with n being the number of operands, and then stored in contiguous memory locations.
-
2.
Input data from Raw are copied to Semi, Eigen, Blas, and Univec. We use meter [m] unit for solutions with UoM validation.
-
3.
The timer is started.
-
4.
The operation is performed 10,000 times, without multi-threading, and results are stored in a contiguous memory location.
-
5.
The timer is stopped, and the time spent for a single operation is calculated dividing the total time by 10,000.
-
6.
The results for each approach are compared for correctness against the result of Raw implementation.
-
7.
All these steps are repeated 1000 times in order to calculate the mean value and the stdev.
The source code for the performance analysis is available at the following locations:
https://gitlab.com/edystan/univec-performance-test
https://gitlab.com/edystan/univec-scaling-test
The first repository contains the performance tests for commonly used methods for both Matrix and VectorC classes, results being displayed in Figs. 2 and 3. In contrast, the second one contains the performance analysis for only two methods (vector dot product and matrix determinant) but for vector dimensions between 2D and 10D and matrices sizes between \(2\times 2\) and \(10\times 10\). For each of the two performance projects, the test results are collected and saved in .csv files, one for each operating system, and available at the previously mentioned addresses. As well, results for these tests are shown in Figs. 4 and 5.
The performance validation was performed on two laptops to simulate real scenarios in two operating systems. The configurations are the following:
-
1.
Lenovo V17 G2 ITL laptop with Intel Core i7-1165G7 at 2.80 GHz, 16 GB RAM. Ubuntu 22.04.2 LTS, Boost 1.74.0, Eigen 3.4.0, Univec 1.2, OpenBlas 3.10.0, Lapack 3.10.0. Compiled with GCC 11.2.0 with Release configuration.
-
2.
Apple MacBook Pro laptop with Apple M2 Max CPU at max. 3.49 GHz, 32 GB RAM. macOS Ventura 13.4.1, Boost 1.82.0, Eigen 3.4.0, Univec 1.2, Accelerate-1 (for Blas/Lapack). Compiled with Apple Clang version 14.0.3 with Release configuration.
We can conclude that Univec performs in line with the other solutions, without any significant overhead, but with the addition of compile-time validation and a reasonable interface. In the performance analysis, we can see that Blas often shows poor performance, but we assume two factors cause this:
-
1.
The overhead of calling a Fortran function from C++ code (when applicable).
-
2.
The fact that we perform a BLAS call for each vector: we realize that BLAS can be used for some operations, but not all, in a SIMD (single instruction multiple data) fashion, which could mitigate the function calling overhead.
In addition to this, we noticed an anomaly on the calculation of dot product for 8D vectors: as shown in Fig. 4a, we can see that we have a performance hit on Linux/GCC platform, which seems to only appear at this specific dimension. We do not have a definitive explanation for this phenomenon, however we suspect that is a bug on the GCC optimization algorithm, because the same issue is not present in macOS/Clang environment, as show in Fig. 4b.
Another anomaly we found in Fig. 5b, is that, for macOS, the timing of determinant do not scale well with the increasing of dimensionality. We believe that the causes of this behavior are:
-
1.
The use the Gaussian elimination method for matrix bigger than \(4\times 4\), which is not the most efficient method available (BLAS uses the more efficient PLU decomposition).
-
2.
Some different optimization settings applied by the Apple Clang compiler.
We plan to analyze and fix these optimization issues in the near future, in order to have performance in line with other implementations.
Limitations and future plans
Our strongest limitation is that, currently, our solution only works with Clang of version higher or equal to 14. This is caused by our decision to use the latest C++20 features like requires and constexpr/consteval. Compatibility with GCC is limited at this moment because we use the __declspec(property) attribute to give access to the vector components. Univec was not tested under the MSVC or icc compiler, however we do not expect blocking issues as long as C++20 is supported.
The use of Boost.Units as an underlying library for Univec has several non-negligible weak points that, unfortunately, seem to have no solution in the near future. The first limitation is that this library is available only as part of a more comprehensive framework, Boost, which many software developers often see as a heavy dependency. The second limitation is that the current implementation is based on heavy use of Boost Metaprogramming Library (MPL) and template meta-programming techniques, which produce error messages challenging to understand for the non-experienced software developers.
In “\(W^- \rightarrow e^- + {\bar{\nu }}_e\) decay”, we present an example of an elementary particle physics calculus implementation. However, the use of SI units is not encouraged and is not widespread in this field. We plan in a near future to add support to Boost::Units6 for natural units, allowing more easy adoption of our solution by the HEP community.
There is a proposal to introduce the support for UoM-aware units directly in the standard language (see Mateusz Pusz’s talk at CppCon 201931). This approach will solve the problems presented above and will provide a more reliable solution with a less steep learning curve. We plan to create another implementation which uses a standard library implementation when it will become available. However, it will take several years until such implementation will find its way into the C++ standard library. Last, but not least, we plan to introduce in the near future a SIMD optimization (e.g. SSE 2 or the newer AVX-512), which can increase the performance by an order of magnitude when working with vectors or matrices.
Conclusions
In this paper, we presented Univec, our solution for UoM-validation in software development, aiming to improve the use of vector and matrix calculations in C++ development. After a brief overview of the existing UoM solutions, we discussed their limitations and presented our solution, with several specific user-case scenarios.
The elaboration of Univec started as an internal project during the designing phase of our Betaboltz32 project. While developing this project, we realized the benefits of integrating the UoM analysis directly into our source code, virtually removing the most common causes of mistakes. Even if this solution does not remove all the sources of error, Univec allowed us to focus on the main development workflow, increasing confidence in our implementation.
We plan to also create to a native implementation when a UoM-aware implementation will be published in the C++ standard library and we hope that similar solutions will be widely accepted in the development of advanced computational calculus for the scientific community.
Data availability
All data generated or analysed during this study are included in this published article and its supplementary information files.
References
Mayerhofer, T., Wimmer, M. & Vallecillo, A. Adding uncertainty and units to quantity types in software models. In Proceedings of the 2016 ACM SIGPLAN International Conference on Software Language Engineering, SLE 2016, 118–131. https://doi.org/10.1145/2997364.2997376 (Association for Computing Machinery, 2016).
McKeever, S., Bennich-Björkman, O. & Salah, O.-A. Unit of measurement libraries, their popularity and suitability. Softw. Pract. Exp. 51, 711–734. https://doi.org/10.1002/spe.2926 (2021).
Preussner, G. M. Dimensional Analysis in Programming Languages. https://gmpreussner.com/research/dimensional-analysis-in-programming-languages (2018).
Apple Inc. Swift Language. https://swift.org (2022).
Kennedy, A. Types for Units-of-Measure: Theory and Practice. In Central European Functional Programming School: Third Summer School, CEFP 2009, Budapest, Hungary, May 21–23, 2009 and Komárno, Slovakia, May 25–30, 2009, Revised Selected Lectures, Lecture Notes in Computer Science (Horváth, Z., Plasmeijer, R. & Zsók, V., eds.), 268–305. https://doi.org/10.1007/978-3-642-17685-2_8 (Springer, 2010).
Schabel, M. C. & Watanabe, S. Chapter 44 boost.units 1.1.0-1.80.0. https://www.boost.org/doc/libs/1_80_0/doc/html/boost_units.html (2020).
Petty, G. W. Automated computation and consistency checking of physical dimensions and units in scientific programs. Softw. Pract. Exp. 31, 1067–1076. https://doi.org/10.1002/spe.401 (2001).
Grecco, H. Pint. https://github.com/hgrecco/pint (2022).
Lönnblad, L. CLHEP-a project for designing a C++ class library for high energy physics. Comput. Phys. Commun. 84, 307–316. https://doi.org/10.1016/0010-4655(94)90217-8 (1994).
Jacob, B. & Guennebaud, G. Eigen is a c++ template library for linear algebra: Matrices, vectors, numerical solvers, and related algorithms. https://eigen.tuxfamily.org/ (2010).
Dembinski, H., Nellen, L., Reininghaus, M. & Ulrich, R. Technical Foundations of CORSIKA 8: New Concepts for Scientific Computing. In Proceedings of 36th International Cosmic Ray Conference—PoS(ICRC2019), vol. 358, 236. https://doi.org/10.22323/1.358.0236(2019).
Heck, D., Knapp, J., Capdevielle, J.-N., Schatz, G. & Thouw, T. CORSIKA: A Monte Carlo Code to Simulate Extensive Air Showers (Tech. Rep, Institut national de physique nucléaire et de physique des particules, 1998).
Moene, M. PhysUnits-CT-Cpp11. https://github.com/martinmoene/PhysUnits-CT-Cpp11 (2013).
IEEE Standard for Floating-Point Arithmetic. IEEE Std 754-2019 (Revision of IEEE 754-2008) 1–84. https://doi.org/10.1109/IEEESTD.2019.8766229(2019). Conference Name: IEEE Std 754-2019 (Revision of IEEE 754-2008).
Univec article examples -GitLab.
Bethe, H. Zür Theorie des Durchgangs schneller Korpuskularstrahlen durch Materie. Ann. Phys. 397, 325–400. https://doi.org/10.1002/andp.19303970303 (1930).
Bloch, F. Zur Bremsung rasch bewegter Teilchen beim Durchgang durch Materie. Ann. Phys. 408, 285–320. https://doi.org/10.1002/andp.19334080303 (1933).
Bloch, F. Bremsvermögen von Atomen mit mehreren Elektronen. Z. Phys. 81, 363–376. https://doi.org/10.1007/BF01344553 (1933).
Thomson, M. Modern Particle Physics (Cambridge University Press, 2013).
Gcc, the gnu compiler collection—website. https://gcc.gnu.org.
Clang: a c language family frontend for llvm—website. https://clang.llvm.org.
gcovr—website. https://gcovr.com/en/stable/.
Googletest repository. https://github.com/google/googletest.
Gitlab website. https://gitlab.com.
Doxygen website. https://doxygen.nl.
BLAS (basic linear algebra subprograms).
LAPACK—linear algebra PACKage (2023).
OpenBLAS : An optimized BLAS library (2023).
The LAPACKE c interface to LAPACK.
Inc, A. Accelerate.
Pusz, M. A c++ approach to physical units (2019).
Renda, M., Ciubotaru, D. & Banu, C. Betaboltz: A Monte-Carlo simulation tool for gas scattering processes. Comput. Phys. Commun. 267, 108057. https://doi.org/10.1016/j.cpc.2021.108057 (2021).
Acknowledgements
This study was supported by the Romanian Ministry of Research, Innovation and Digitization through the PN23210104 and ATLAS CERN-RO Grants.
Author information
Authors and Affiliations
Contributions
E.S.: software, validation, writing—original draft, visualization. D.C.: software, validation, writing—review and editing. M.R.: conceptualization, software, writing—review and editing, supervision. C.A.: resources, writing—review and editing, supervision, project administration, funding acquisition.
Corresponding author
Ethics declarations
Competing interests
The authors declare no competing interests.
Additional information
Publisher's note
Springer Nature remains neutral with regard to jurisdictional claims in published maps and institutional affiliations.
Rights and permissions
Open Access This article is licensed under a Creative Commons Attribution 4.0 International License, which permits use, sharing, adaptation, distribution and reproduction in any medium or format, as long as you give appropriate credit to the original author(s) and the source, provide a link to the Creative Commons licence, and indicate if changes were made. The images or other third party material in this article are included in the article’s Creative Commons licence, unless indicated otherwise in a credit line to the material. If material is not included in the article’s Creative Commons licence and your intended use is not permitted by statutory regulation or exceeds the permitted use, you will need to obtain permission directly from the copyright holder. To view a copy of this licence, visit http://creativecommons.org/licenses/by/4.0/.
About this article
Cite this article
Stan, E.G., Ciubotaru, D.A., Renda, M. et al. A new advance on dimensional-aware scalar, vector and matrix operations in C++. Sci Rep 13, 16666 (2023). https://doi.org/10.1038/s41598-023-43683-w
Received:
Accepted:
Published:
Version of record:
DOI: https://doi.org/10.1038/s41598-023-43683-w







