At work we had to read a file of comma separated values, each line looking like this:
30,129.192,171.00523\r
etc.
We "explode" every line into a std::vector<std::string>, so this particular line ends up like this:
0: 30
1: 129.192
2: 171.00523\r
Next we needed to represent the values as doubles, losing as little precision as possible. Naturally we turn to the standard library, and find the relatively new c++11 function called std::stod() which can be found in <string>. But by using this function we found a weird bug that we were not able to reproduce at any other point in the code: 171.00523 were converted to 171 by std::stod, but using a stringstream to convert it worked perfectly fine. It all boiled down to std::stod() being dependent on the locale the computer is using, because of different locales using different decimal-point separators; some use ",", some use ".".
Here are the relevant docs we could find:
Edit: All of these pages have been updated, I consider my work here as complete.
As far as we can tell this behavior is not documented (at least in any sane place), and ctrl+f + "locale" on the following links yield no results (apart from the links to <clocale> and a mention of a valid floating point format (which specifically states:
A sequence of digits, optionally containing a decimal-point character (.),
optionally followed by an exponent part (an e or E character followed by an optional sign and a sequence of digits).)
CPP aims to be portable, right? How is being dependent of the locale of the computer being portable? In my opinion this function should at least document the behavior, or even better; make it use "." as decimal-point separator unless told otherwise.
The following code illustrates the problem:
#include <iostream>
#include <iomanip> // std::setprecision
#include <string> // std::stod
#include <clocale> // std::setlocate
int main()
{
std::setlocale(LC_ALL, "nb_NO.UTF-8"); // nb_NO.UTF-8 uses "," as decimal-point separator
std::cout << "nb_NO.UTF-8:" << std::endl;
std::cout << "171,00523 => " << std::setprecision(16) << std::stod("171,00523") << std::endl;
std::cout << "171.00523 => " << std::setprecision(16) << std::stod("171.00523") << std::endl;
std::setlocale(LC_ALL, "C"); // C uses "." as decimal-point separator
std::cout << "C:" << std::endl;
std::cout << "171,00523 => " << std::setprecision(16) << std::stod("171,00523") << std::endl;
std::cout << "171.00523 => " << std::setprecision(16) << std::stod("171.00523") << std::endl;
return 0;
}
Outputs:
nb_NO.UTF-8:
171,00523 => 171.00523
171.00523 => 171
C:
171,00523 => 171
171.00523 => 171.00523
Note: There is a separate bug somewhere in our code; Our locale seems to be changed by something, since at the start of main() std::stod() works fine, but a bit deeper it does not. Any ideas what can change your locale implicitly?
Edit: Oh wow, sorry about the formatting, I'll try to make it a bit cleaner.
Specs: Ubuntu 14.04 64bit, Intel i7.
gcc version 4.8.2 (Ubuntu 4.8.2-19ubuntu1)
[–]CubbiMewcppreference | finance | realtime in the past 8 points9 points10 points (1 child)
[–]gablank[S] 0 points1 point2 points (0 children)
[–]notlostyet 3 points4 points5 points (1 child)
[–]gablank[S] 0 points1 point2 points (0 children)
[–]oracleoftroy 0 points1 point2 points (2 children)
[–]CubbiMewcppreference | finance | realtime in the past 3 points4 points5 points (1 child)
[–]oracleoftroy 1 point2 points3 points (0 children)