Updated:
I have been trying all methods I could find in stackoverflow, and still could not find a solution.
My point is, I have a string "23.46" and would like to transfer it to double or float anyway. This is in order to be used in another library.
But no matter how I trancate,floor,*100,add,round, it always gives me 24.4600000001 or something like this.
I know there are some precision issue while transfer. But I do need a way to give me a number that double d = 24.46 precisely.
==============================================================================
I have many string values and some of them are double with converted precision as below:
char pt[100];
sprintf(pt, "%.2lf", i);
return string(pt);
Now on the other side of the code, I need to convert the strings back to double, but I tried strtod and atof with precision loss.
My questions are:
what is the good way to check if a string could be a double?
how to convert string back to double with given precision? I only need it to %.2lf be like:
0.21, 35.45, ...
Thanks so much!
Given that you say that using std::strtod is not giving you a solution to the problem, you can use stringstreams to parse strings as doubles, you can also use its flags to assert if the contents of the string are convertible.
Here is an example with some conversions back and forth, and with checks to see if the whole string (not just some digits in it), is parseable as double:
Live demo
#include <iostream>
#include <sstream>
#include <iomanip>
int main()
{
std::string str = "23.4k7"; //string with a character in the middle
std::istringstream ss(str); //put string in a stream
double num;
ss >> num; //convert string to double
if(!ss.fail() && ss.eof()) { //check if the whole string is parseable
std::cout << "is parseable" << std::endl;
}
else {
std::cout << "is not parseable";
return EXIT_FAILURE;
}
std::stringstream to_num;
to_num << std::fixed << std::setprecision(2) << num; //double to string 2 decimal places
std::cout << to_num.str();
to_num >> num; //final conversion to double
}
Since the string has an alphabetic character in it, this will output:
is not parseable
But if you use a valid number it will output the converted value:
string str:
234.2345
Output:
is parseable
234.23
Note that you could use
Live demo
if(ss >> num)
std::cout << "is parseable";
This, however, has a weakness, it will still parse if you have for instance 123.45rt56, 123.45 will be parsed, the rest will be discarded, the way it is in the sample code, if the string has any character, it will return an error. You can choose the more appropriate way for your needs.
Related
How do you convert a float to a string in C++ while specifying the precision & number of decimal digits?
For example: 3.14159265359 -> "3.14"
A typical way would be to use stringstream:
#include <iomanip>
#include <sstream>
double pi = 3.14159265359;
std::stringstream stream;
stream << std::fixed << std::setprecision(2) << pi;
std::string s = stream.str();
See fixed
Use fixed floating-point notation
Sets the floatfield format flag for the str stream to fixed.
When floatfield is set to fixed, floating-point values are written using fixed-point notation: the value is represented with exactly as many digits in the decimal part as specified by the precision field (precision) and with no exponent part.
and setprecision.
For conversions of technical purpose, like storing data in XML or JSON file, C++17 defines to_chars family of functions.
Assuming a compliant compiler (which we lack at the time of writing),
something like this can be considered:
#include <array>
#include <charconv>
double pi = 3.14159265359;
std::array<char, 128> buffer;
auto [ptr, ec] = std::to_chars(buffer.data(), buffer.data() + buffer.size(), pi,
std::chars_format::fixed, 2);
if (ec == std::errc{}) {
std::string s(buffer.data(), ptr);
// ....
}
else {
// error handling
}
The customary method for doing this sort of thing is to "print to string". In C++ that means using std::stringstream something like:
std::stringstream ss;
ss << std::fixed << std::setprecision(2) << number;
std::string mystring = ss.str();
You can use C++20 std::format:
#include <format>
int main() {
std::string s = std::format("{:.2f}", 3.14159265359); // s == "3.14"
}
or the fmt::format function from the {fmt} library, std::format is based on (godbolt):
#include <fmt/core.h>
int main() {
std::string s = fmt::format("{:.2f}", 3.14159265359); // s == "3.14"
}
where 2 is a precision.
It is not only shorter than using iostreams or sprintf but also significantly faster and is not affected by the locale.
Another option is snprintf:
double pi = 3.1415926;
std::string s(16, '\0');
auto written = std::snprintf(&s[0], s.size(), "%.2f", pi);
s.resize(written);
Demo. Error handling should be added, i.e. checking for written < 0.
Here a solution using only std. However, note that this only rounds down.
float number = 3.14159;
std::string num_text = std::to_string(number);
std::string rounded = num_text.substr(0, num_text.find(".")+3);
For rounded it yields:
3.14
The code converts the whole float to string, but cuts all characters 2 chars after the "."
Here I am providing a negative example where your want to avoid when converting floating number to strings.
float num=99.463;
float tmp1=round(num*1000);
float tmp2=tmp1/1000;
cout << tmp1 << " " << tmp2 << " " << to_string(tmp2) << endl;
You get
99463 99.463 99.462997
Note: the num variable can be any value close to 99.463, you will get the same print out. The point is to avoid the convenient c++11 "to_string" function. It took me a while to get out this trap. The best way is the stringstream and sprintf methods (C language). C++11 or newer should provided a second parameter as the number of digits after the floating point to show. Right now the default is 6. I am positing this so that others won't wast time on this subject.
I wrote my first version, please let me know if you find any bug that needs to be fixed. You can control the exact behavior with the iomanipulator. My function is for showing the number of digits after the decimal point.
string ftos(float f, int nd) {
ostringstream ostr;
int tens = stoi("1" + string(nd, '0'));
ostr << round(f*tens)/tens;
return ostr.str();
}
How do you convert a float to a string in C++ while specifying the precision & number of decimal digits?
For example: 3.14159265359 -> "3.14"
A typical way would be to use stringstream:
#include <iomanip>
#include <sstream>
double pi = 3.14159265359;
std::stringstream stream;
stream << std::fixed << std::setprecision(2) << pi;
std::string s = stream.str();
See fixed
Use fixed floating-point notation
Sets the floatfield format flag for the str stream to fixed.
When floatfield is set to fixed, floating-point values are written using fixed-point notation: the value is represented with exactly as many digits in the decimal part as specified by the precision field (precision) and with no exponent part.
and setprecision.
For conversions of technical purpose, like storing data in XML or JSON file, C++17 defines to_chars family of functions.
Assuming a compliant compiler (which we lack at the time of writing),
something like this can be considered:
#include <array>
#include <charconv>
double pi = 3.14159265359;
std::array<char, 128> buffer;
auto [ptr, ec] = std::to_chars(buffer.data(), buffer.data() + buffer.size(), pi,
std::chars_format::fixed, 2);
if (ec == std::errc{}) {
std::string s(buffer.data(), ptr);
// ....
}
else {
// error handling
}
The customary method for doing this sort of thing is to "print to string". In C++ that means using std::stringstream something like:
std::stringstream ss;
ss << std::fixed << std::setprecision(2) << number;
std::string mystring = ss.str();
You can use C++20 std::format:
#include <format>
int main() {
std::string s = std::format("{:.2f}", 3.14159265359); // s == "3.14"
}
or the fmt::format function from the {fmt} library, std::format is based on (godbolt):
#include <fmt/core.h>
int main() {
std::string s = fmt::format("{:.2f}", 3.14159265359); // s == "3.14"
}
where 2 is a precision.
It is not only shorter than using iostreams or sprintf but also significantly faster and is not affected by the locale.
Another option is snprintf:
double pi = 3.1415926;
std::string s(16, '\0');
auto written = std::snprintf(&s[0], s.size(), "%.2f", pi);
s.resize(written);
Demo. Error handling should be added, i.e. checking for written < 0.
Here a solution using only std. However, note that this only rounds down.
float number = 3.14159;
std::string num_text = std::to_string(number);
std::string rounded = num_text.substr(0, num_text.find(".")+3);
For rounded it yields:
3.14
The code converts the whole float to string, but cuts all characters 2 chars after the "."
Here I am providing a negative example where your want to avoid when converting floating number to strings.
float num=99.463;
float tmp1=round(num*1000);
float tmp2=tmp1/1000;
cout << tmp1 << " " << tmp2 << " " << to_string(tmp2) << endl;
You get
99463 99.463 99.462997
Note: the num variable can be any value close to 99.463, you will get the same print out. The point is to avoid the convenient c++11 "to_string" function. It took me a while to get out this trap. The best way is the stringstream and sprintf methods (C language). C++11 or newer should provided a second parameter as the number of digits after the floating point to show. Right now the default is 6. I am positing this so that others won't wast time on this subject.
I wrote my first version, please let me know if you find any bug that needs to be fixed. You can control the exact behavior with the iomanipulator. My function is for showing the number of digits after the decimal point.
string ftos(float f, int nd) {
ostringstream ostr;
int tens = stoi("1" + string(nd, '0'));
ostr << round(f*tens)/tens;
return ostr.str();
}
I am using C++ and I would like to format doubles in the following obvious way. I have tried playing with 'fixed' and 'scientific' using stringstream, but I am unable to achieve this desired output.
double d = -5; // print "-5"
double d = 1000000000; // print "1000000000"
double d = 3.14; // print "3.14"
double d = 0.00000000001; // print "0.00000000001"
// Floating point error is acceptable:
double d = 10000000000000001; // print "10000000000000000"
As requested, here are the things I've tried:
#include <iostream>
#include <string>
#include <sstream>
#include <iomanip>
using namespace std;
string obvious_format_attempt1( double d )
{
stringstream ss;
ss.precision(15);
ss << d;
return ss.str();
}
string obvious_format_attempt2( double d )
{
stringstream ss;
ss.precision(15);
ss << fixed;
ss << d;
return ss.str();
}
int main(int argc, char *argv[])
{
cout << "Attempt #1" << endl;
cout << obvious_format_attempt1(-5) << endl;
cout << obvious_format_attempt1(1000000000) << endl;
cout << obvious_format_attempt1(3.14) << endl;
cout << obvious_format_attempt1(0.00000000001) << endl;
cout << obvious_format_attempt1(10000000000000001) << endl;
cout << endl << "Attempt #2" << endl;
cout << obvious_format_attempt2(-5) << endl;
cout << obvious_format_attempt2(1000000000) << endl;
cout << obvious_format_attempt2(3.14) << endl;
cout << obvious_format_attempt2(0.00000000001) << endl;
cout << obvious_format_attempt2(10000000000000001) << endl;
return 0;
}
That prints the following:
Attempt #1
-5
1000000000
3.14
1e-11
1e+16
Attempt #2
-5.000000000000000
1000000000.000000000000000
3.140000000000000
0.000000000010000
10000000000000000.000000000000000
There is no way for a program to KNOW how to format the numbers in the way that you are describing, unless you write some code to analyze the numbers in some way - and even that can be quite hard.
What is required here is knowing the input format in your source code, and that's lost as soon as the compiler converts the decimal input source code into binary form to store in the executable file.
One alternative that may work is to output to a stringstream, and then from that modify the output to strip trailing zeros. Something like this:
string obvious_format_attempt2( double d )
{
stringstream ss;
ss.precision(15);
ss << fixed;
ss << d;
string res = ss.str();
// Do we have a dot?
if ((string::size_type pos = res.rfind('.')) != string::npos)
{
while(pos > 0 && (res[pos] == '0' || res[pos] == '.')
{
pos--;
}
res = res.substr(pos);
}
return res;
}
I haven't actually tired it, but as a rough sketch, it should work. Caveats are that if you have something like 0.1, it may well print as 0.09999999999999285 or some such, becuase 0.1 can not be represented in exact form as a binary.
Formatting binary floating-point numbers accurately is quite tricky and was traditionally wrong. A pair of papers published in 1990 in the same journal settled that decimal values converted to binary floating-point numbers and back can have their values restored assuming they don't use more decimal digits than a specific constraint (in C++ represented using std::numeric_limits<T>::digits10 for the appropriate type T):
Clinger's "How to read floating-point numbers accurately" describes an algorithm to convert from a decimal representation to a binary floating-point.
Steele/White's "How to print floating-point numbers accurately" describes how to convert from a binary floating-point to a decimal decimal value. Interestingly, the algorithm even converts to the shortest such decimal value.
At the time these papers were published the C formatting directives for binary floating points ("%f", "%e", and "%g") were well established and they didn't get changed to the take the new results into account. The problem with the specification of these formatting directives is that "%f" assumes to count the digits after the decimal point and there is no format specifier asking to format numbers with a certain number of digits but not necessarily starting to count at the decimal point (e.g., to format with a decimal point but potentially having many leading zeros).
The format specifiers are still not improved, e.g., to include another one for non-scientific notation possibly involving many zeros, for that matter. Effectively, the power of the Steele/White's algorithm isn't fully exposed. The C++ formatting, sadly, didn't improve over the situation and just delegates the semantics to the C formatting directives.
The approach of not setting std::ios_base::fixed and using a precision of std::numeric_limits<double>::digits10 is the closest approximation of floating-point formatting the C and C++ standard libraries offer. The exact format requested could be obtained by getting the digits using using formatting with std::ios_base::scientific, parsing the result, and rewriting the digits afterwards. To give this process a nice stream-like interface it could be encapsulated with a std::num_put<char> facet.
An alternative could be the use of Double-Conversion. This implementation uses an improved (faster) algorithm for the conversion. It also exposes interfaces to get the digits in some form although not directly as a character sequence if I recall correctly.
You can't do what you want to do, because decimal numbers are not representable exactly in floating point format. In otherwords, double can't precisely hold 3.14 exactly, it stores everything as fractions of powers of 2, so it stores it as something like 3 + 9175/65536 or thereabouts (do it on your calculator and you'll get 3.1399993896484375. (I realize that 65536 is not the right denominator for IEEE double, but the gist of it is correct).
This is known as the round trip problem. You can't reliable do
double x = 3.14;
cout << magic << x;
and get "3.14"
If you must solve the round-trip problem, then don't use floating point. Use a custom "decimal" class, or use a string to hold the value.
Here's a decimal class you could use:
https://stackoverflow.com/a/15320495/364818
I am using C++ and I would like to format doubles in the following obvious way.
Based on your samples, I assume you want
Fixed rather than scientific notation,
A reasonable (but not excessive) amount of precision (this is for user display, so a small bit of rounding is okay),
Trailing zeros truncated, and
Decimal point truncated as well if the number looks like an integer.
The following function does just that:
#include <cmath>
#include <iomanip>
#include <sstream>
#include <string>
std::string fixed_precision_string (double num) {
// Magic numbers
static const int prec_limit = 14; // Change to 15 if you wish
static const double log10_fuzz = 1e-15; // In case log10 is slightly off
static const char decimal_pt = '.'; // Better: use std::locale
if (num == 0.0) {
return "0";
}
std::string result;
if (num < 0.0) {
result = '-';
num = -num;
}
int ndigs = int(std::log10(num) + log10_fuzz);
std::stringstream ss;
if (ndigs >= prec_limit) {
ss << std::fixed
<< std::setprecision(0)
<< num;
result += ss.str();
}
else {
ss << std::fixed
<< std::setprecision(prec_limit-ndigs)
<< num;
result += ss.str();
auto last_non_zero = result.find_last_not_of('0');
if (result[last_non_zero] == decimal_pt) {
result.erase(last_non_zero);
}
else if (last_non_zero+1 < result.length()) {
result.erase(last_non_zero+1);
}
}
return result;
}
If you are using a computer that uses IEEE floating point, changing prec_limit to 16 is unadvisable. While this will let you properly print 0.9999999999999999 as such, it also prints 5.1 as 5.0999999999999996 and 9.99999998 as 9.9999999800000001. This is from my computer, your results may vary due to a different library.
Changing prec_limit to 15 is okay, but it still leads to numbers that don't print "correctly". The value specified (14) works nicely so long as you aren't trying to print 1.0-1e-15.
You could do even better, but that might require discarding the standard library (see Dietmar Kühl's answer).
I am using stringstream to parse float from string.
std::stringstream strs(cp.val);
strs.precision(5);
strs<<std::setprecision(5);
float x; strs>>x;
however the set precision functions do not seem to work..
is there any way to force precision in parsing not printing ?
The precision (along with things like fixed and scientific) only affect output; input will parse anything that looks like a numeric value, extracting all of the characters which could possibly be part of any numeric value. (This includes hex characters, and the 'X' which might occur for integral input.) If you want to limit the format in any way, you'll have to read it as a string, validate the format, and then use std::istringstream to convert it.
stringstram does not allow precision on parsing, but you may set the double precision after parsing.
E.g.
#include <iostream>
#include <sstream>
#include <iomanip>
#include <cmath>
using namespace std; //do not use that in real project.
int main()
{
// Initial declarations
stringstream ss("13.321646");
double x = 0.0;
// Parse the double
ss >> x;
// Set the double precision to 2decimals
double roundedX = round(x*100)/100;
// output solution
cout << x << endl;
cout << setprecision(5) << x << endl;
cout << roundedX << endl;
return 0;
}
Obvious note: That allow to reduce precision, not to improve it.
hello i have a problem with converting a string of numbers to integer.
the problem is that using atoi() to convert the string to integer i loose the leading zeros.
can you please tell me a way to do that without loosing the leading zeros?
#include <fstream>
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
struct Book{
int id;
string title;
};
struct Author{
string firstName;
string lastName;
};
Author authorInfo[200];
Book bookInfo[200];
void load ( void )
{
int count = 0;
string temp;
ifstream fin;
fin.open("myfile.txt");
if (!fin.is_open())
{
cout << "Unable to open myfile.txt file\n";
exit(1);
}
while (fin.good())
{
getline(fin, temp, '#');
bookInfo[count].id = atoi(temp.c_str());
getline(fin, bookInfo[count].title, '#');
getline(fin, authorInfo[count].firstName, '#');
getline(fin, authorInfo[count].lastName, '#');
count++;
}
fin.close();
}
Ok, so I don't think you actually WANT to store the leading zeros. I think you want to DISPLAY a consistent number of digits in the output.
So, for example, to display a fixed size id with 5 digits [note that an id of 100000 will still display in 6 digits - all it does here is make sure it's always at least 5 digits, and fill it with '0' if the number is not big enough], we could do:
std::cout << std::setw(5) << std::setfill('0') << id << ...
Alternatively, as suggested in other answers, you don't want to use the ID in a form that is an integer, you could just store it as a string - unless you are going to do math on it, all that it changes is that it takes up a tiny bit more memory per book.
An integer does not have leading zeroes. Or perhaps, more correctly, it has between zero and an infinite number of them. The numbers 42, 042 and 000000042 (other than in the source code where a leading 0 indicates a different base) are all forty-two.
If you want to keep the leading zeroes, either leave it as a string or store more information somewhere as to how big the original string was. Something like this would be a good start:
#include <iostream>
#include <iomanip>
#include <cstring>
#include <cstdio>
#include <cstdlib>
int main (void) {
// Test data.
const char *sval = "0042";
// Get original size.
int size = strlen (sval);
// Convert to int (without leading 0s).
// strtol would be better for detecting bad numbers.
int ival = atoi (sval);
// Output details.
std::cout << sval << " has size of " << size << ".\n";
std::cout << "Integer value is " << ival << ".\n";
std::cout << "Recovered value is " << std::setw(size)
<< std::setfill('0') << ival << ".\n";
return 0;
}
which outputs:
0042 has size of 4.
Integer value is 42.
Recovered value is 0042.
A = strlen(string) returns the number of characters in your string (say number of digits comprehensive of leading zeros)
B = log10(atoi(string)) + 1 returns the number of digits in your number
A - B => number of leading zeros.
Now you can format those as you prefer.
There's no such thing as "leading zeros" in a number. "Leading zeros" is a property of a specific notation, like decimal ASCII representation of a number. Once you convert that notation to a conceptually abstract numerical representation, such metric as "number of leading zeros" is no longer applicable (at least in decimal terms). It is lost without a trace.
A number is a number. It doesn't have any "zeros", leading or otherwise.
The only thing you can do is to memorize how many leading zeros you had in the original notation (or how wide was the field), and then later, when you will convert the number back to decimal ASCII representation, re-create the proper number of leading zeros using that stored information.
BTW, in your case, when the input number represents a book ID with some pre-determined formatting (like leading zeros), you might consider a different approach: don't convert your book ID to int. Keep it as a string. It is not like you are going to have to perform arithmetic operations on book IDs, is it? Most likely all you'll need is relational and equality comparisons, which can be performed on strings.
I have encountered this type of problem last month!
I think you can use the Format() method provided by Class CString:
CString::Format() formats and stores a series of characters and values in the CString. Each optional argument (if any) is converted and output according to the corresponding format specification in pszFormat or from the string resource identified by nFormatID.
For example:
CString m_NodeName;
m_NodeName.Format(_T("%.4d"),Recv[2]*100+Recv[3]);
// %.4d means the argument will be formatted as an integer,
// 4 digits wide, with unused digits filled with leading zeroes
For the detail you can find here:
http://msdn.microsoft.com/zh-cn/library/18he3sk6(v=vs.100).aspx
If you need the leading zeros, then int is not the correct data type to use. In your case you may be better off just storing the original string.
There is no way of storing an int with leading 0s.
What you may want to do instead, is have a class do it for you:
class intWithLeadingZeros {
int number;
int numberOfLeadingZeros;
intWithLeadingZeros( string val )
{
// trivial code to break down string into zeros and number
}
string toString() {
// trivial code that concatenates leading 0s and number
}
};