What is optimization in arithmetic operations? How can I optimize my equations or functions? Which arithmetic operation is faster than another one? Where should I optimize?

Optimization is one of the important part of programming but we should note that it is not as important in C++ in most cases for modern CPUs and GPUs today. Do not spend too much time to optimize if it is not needed. In this post, we will explain where you should optimize and 5 ways to optimize C++ arithmetic operations.

## What is Optimization ?

Mathematical optimization is really important in programming. **Mathematical Optimization** also called **Mathematical Programming** is the selection of the best mathematical elements or functions about some criterion, from a set of available alternatives. In programming, optimization problems of all sorts arise in all quantitative disciplines from computer science and engineering to operations research and economics, and the development of optimal solutions to problems has been of interest in mathematics for centuries. Sometimes it’s not enough to just get an answer – sometimes it’s desirable to get the best and most efficient answer.

## Where and how can I optimize in programming ?

Today we have very high-speed computers and many new mathematical and logical instruction sets in our CPUs and GPUs. In general, if you have single operations, in this modern world of powerful compilers running on advanced modern hardware it’s not as critical as it used to be to spend excessive time optimizing your applications. Don’t forget that efficient coding takes time. Optimization may take at least twice your coding time. For example, most accounting applications don’t require optimizations when doing sum add calculating taxes and other expenses. Most of the operations are done by a single click in a single method or function which ends less than in milliseconds. These kinds of applications may not require much optimization, if any.

If you have a lot of datapoints – pixels, videos, data – to handle with heavy iterating, repeating computations, heavy loops or do-whiles(), recursive functions then you should focus on optimization in those areas instead. This will make your process faster and more robust for future extensions.

### 1. Simplify your equations

Try to simplify your equations. There are simplification methods in some of the mathematical applications. You can use equation editors like Matlab, Mathematica, Wolfram Alpha, Mapple etc. At least try to simplify your equations on paper.

Sometimes terms in math can be faster than you expected. for example division by 2 is faster than multiplication by 0.5. In many equations, these kinds of terms are canceled out.

Note that the compiler cannot find these simplifications, but you can. Eliminating a few expensive operations inside an inner loop can speed your program more than days working on other parts.

### 2. Focus on Modern CPU and GPU Architectures

Optimization methods are also evolving because of many advances in CPU and GPU architectures. Optimization for CPU architectures requires a good assembler programming language. You should know well about how C++ transforms your codes to these machine codes. This will help you in understanding optimization in that architecture.

On modern CPUs and GPUs, floating-point operations have almost the same throughput as integer operations. In compute-intensive programs like ray tracing. This leads to a negligible difference between integer and floating-point costs. This means you should not go out of your way to use integer operations.

The difference between math on integers, fixed points, 32-bit floats, and 64-bit doubles is not as big as you might think. Double-precision floating-point operations may not be slower than single-precision floats, particularly on 64-bit machines. Modern CPUs and GPUs are modernized for the 64bits and using double precision, which means there is no speed change between floats and doubles. Thus, in most cases, ray tracers run faster using all doubles than all floats on the same machine.

### 3. You should know your compiler options

Another thing is you should know well about optimization options -O0, -O1 -O2, and other necessary options required for the new microchip architectures. These options may improve the performance of your methods or functions.

Also, note that a *debug *version is also noticeably slower than a *release* version. Thus your final tests should be on the release version.

### 4. Use operators wisely

Operators are the important part. You should think of operators with a focused CPU/GPU architecture. In general,

- For basic
**data types**, use the operators + , – , * , and / instead of the operators += , -= , *= , and /= - For the most
**classes**, use the operators += , -= , *= , and /= , instead of the operators + , – , * , and / - If there is integer multiplication and division and there is a possibility to use bit shifting operations such as >> and <<, use bit shifting.

### 5. Test and improve your code speed

The best way to understand which method or function is faster is to test this code and measure the duration elapsed. You can use **SetPriorityClass()** method to set priority to `REALTIME_PRIORITY_CLASS`

.

For example, this VCL example below (with a Memo and Button) can be used to test the speed of your methods.

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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
//--------------------------------------------------------------------------- #include <vcl.h> #include <chrono> #pragma hdrstop #include "Optimization_Arithmetics_Unit1.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; #define MAXIT 10000000000 //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { UInt64 i; double x = M_PI, y = M_PI, z; std::chrono::duration<double> diff0, diff; SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS); //-------------------------------------------- auto start = std::chrono::steady_clock::now(); for( i = 0; i<MAXIT; i++ ) { // no operation here } auto end = std::chrono::steady_clock::now(); diff0 = end-start; Memo1->Lines->Add("No Operation Loop:"+ FloatToStr(diff0.count()) ); //-------------------------------------------- start = std::chrono::steady_clock::now(); for( i = 0; i<MAXIT; i++ ) { // Add your function or method here } end = std::chrono::steady_clock::now(); diff = end-start; Memo1->Lines->Add( L"Diff: " + FloatToStr(diff.count() - diff0.count() ) ); } //--------------------------------------------------------------------------- |

These kind of tests can be done in FMX applications and in Console applications too.

**C++ Builder is the easiest and fastest C and C++ IDE for building simple or professional applications on the Windows, MacOS, iOS & Android operating systems. It is also easy for beginners to learn with its wide range of samples, tutorials, help files, and LSP support for code. RAD Studio’s C++ Builder version comes with the award-winning VCL framework for high-performance native Windows apps and the powerful FireMonkey (FMX) framework for cross-platform UIs. **

**There is a free C++ Builder Community Edition for students, beginners, and startups; it can be downloaded from here. For professional developers, there are Professional, Architect, or Enterprise versions of C++ Builder and there is a trial version you can download from here.**