Wednesday 11 April 2018

C++17: insert_or_assign - new API for associative containers

1. Before C++17
This new API ticks a few boxes for our daily programming. Think of the scenario that insert into the container if the key does not exist and update the value if it does exist. Before C++17 it has to use the combination of the following 3 calls as shown in Figure 1.
    - find
    - insert/emplace
    - operator []

Figure 1. Implementation before C++17

Note: emplace() is recommended other than insert() for better performance.

The reason why not use operator [] directly, please refer to Item 24 in [1]. There Scott Meyer has detailed discussion about the performance between operator [] and insert.

2. C++17
From C++17 on the solutions shown in Figure 1 can be replace with this new API - insert_or_assign() as shown in Figure 2.

Figure 2. Implementation in C++17 with the New API

I have looked at the assembly for the code under VS2015 and this is no performance penalty. Therefore feel free and happy to use.


Bibliography:
[1] Scott Meyers, Effectie STL 50 Specific Ways to Improve Your Use of the Standard Template Library



Tuesday 10 April 2018

C++11: a pitfall in std::to_string(float) and std::to_string(double)

1. Root cause
The problem with these two functions is that the precision of the conversion is hard coded as 6 decimals and it is not possible to adjust it.

2. What happened to me?
I made such a mistake when implementing one of services. It is to take live market FX price as input to compute a user-defined price, simple cases like mid price or WAP (weighted average price), convert the price into string (pass to the down stream service via XML), and then reconstruct or compute numeric risk values. It works OK for most currencies but not for JPY. 

It sounds bizarre but the fundamental issue is that the live market price based on JPY instruments is already in 6 decimal precision and the following calculations requires higher precision to make sure the reconstruction and risk value computation correct. But std::to_string(double) has only 6 decimal precision and the 6th decimal is rounded. This causes numeric risk computation failure - the value swing around even though the price is in trend.

3. Solution
The std::to_string manual on cppreference only says it "would produce for sufficiently large buf". No mention about conversion precision. Nor there is a second parameter to specify required precision in the function signature. Easy to make mistake. Lesson learned: always keep in mind floating-point number is different from integer in terms of underflow, overflow, comparison and string conversion. And the solution is rather simple - use string stream and io manipulator.