1

I have different stocks with their prices and I want to store them in the, for example std::map or std::unordered_map:

struct Stock
{
    ...
};

using stock_price_t = double;

std::map<stock_price_t, Stock> ordered_stocks;
std::unordered_map<stock_price_t, Stock> unordered_stocks;

Is it good idea use double keys in the dictionaries or better solutions is present?

QuickDzen
  • 247
  • 1
  • 11
  • 2
    What does your Stock structure look like? Better to use something else for key, maybe some kind of stock ID. – kiner_shah Jan 14 '22 at 10:39
  • 4
    You run the risk of losing stuff e.g. adding a key with value (0.1 + 0.2) then looking up key 0.3 might claim it's not there. Also, why do you need to lookup the price? – doctorlove Jan 14 '22 at 10:39
  • 4
    indepenent of the map you shouldn't use floating point numbers for prices or currencies. – 463035818_is_not_an_ai Jan 14 '22 at 10:42
  • 1
    (To add to what others have said, take a look at https://0.30000000000000004.com/) – byxor Jan 14 '22 at 10:47
  • 1
    This thread could be useful: https://stackoverflow.com/questions/6684573/floating-point-keys-in-stdmap – Hari Jan 14 '22 at 10:50
  • 1
    As another approach, I feel like the price of a stock should go into the `Stock` structure, Then you can use a `std::set` or `std::unordered_set` to store your stocks (or a sorted `std::vector` if you want random access and fast iteration). You can use compare functions that `std::lower_bound` or other `std` functions take in to find your stocks (since you are using floating-points, you can use marginal comparison `std::abs(A - B) < epsilon`). – Shahriar Jan 14 '22 at 10:52
  • 1
    another thing is that you shouldn't use floating-point for money. Store the cent value in integer instead, which will also help using it as a key easily – phuclv Jan 14 '22 at 10:58
  • 1
    A good way to store ordered book of stocks is `boost::multi_index` container indexed by stock id and sorted by price. If you need to erase a stock you can look up by id index. If you need to traverse from the lowest price to the highest you can traverse by ordered price index. – otter Jan 14 '22 at 14:08

1 Answers1

3

A std::map has no issue with using doubles as key. It uses < to compare keys and two keys are equivalent when !(a < b) && !(b < a). That's fine. The issues do arise when you expect floating point numbers to be exact when in fact they are not.

For example:

std::map<double,int> m{{0.3,0},{1.0,2},{2.0,2},{3.0,3}};
for (const auto& e : m) std::cout << e.first << " " << e.second << "\n";

Output is:

0.3 0
1 2
2 2
3 3

But now consider this:

auto it = m.find(0.1 + 0.2);
if (it == m.end()) std::cout << "not found\n";

Searching 0.1 + 0.2 will not find the key 0.3, because doubles are not exact and the output is

not found

TL;DR: Do not use floating point numbers for prices or currencies. When you need prices with cents then use int cents:

std::map<int, Stock> ordered_stocks;
for (const auto& e : ordered_stocks) {
      std::cout << "dollars: " << e.first / 100 << "\n";
      std::cout << "stock: " << e.second << "\n";
}
463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185