I have a number of type double. I want to get a part of it. For example,
If the number is 13041004236.980835 I want my program to remove first 4 digits and return 1004236.980835
What is the shortest way to do this in c++?
Thanks!
#include <string>
#include <sstream>
std::stringstream ss;
ss << number;
std::string str = ss.str();
str.erase( 0, 4 );
Here's how to do it with math:
auto digits = floor(log10(number)) + 1;
number = fmod(number, pow(10, digits - 4));
You can use the string stream approach from the other answer as well, but you need to use
ss << std::fixed << std::setprecision(std::numeric_limits<double>::digits10);
To not lose precision (assuming you're using a double).
Convert it into a string, shorten it and convert it back.
Related
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.
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've used setprecision(8), but when I count asin(1) it returns 0.017452406 (10 digits, not 8!) What can be done there?
In order to fix the problem with decimal digits you need to use std::fixed.
As explaned in C++ Reference
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.
To answer your requirement from the comments: "I need to make number (both integer and decimal parts) to be displayed in max 8 digits." You could use an ostringstream.
#include <iostream>
#include <sstream>
#include <string>
#include <iomanip>
int main(){
std::ostringstream ss; // declare your string stream
ss << std::setprecision(16); // set a high precision to avoid rounding
// Insert your float to the string stream
float f = 0.123456789;
ss << f;
// Get the string from the stream
std::string f_str = ss.str();
// Print
std::cout << f_str.substr(0, 8 + 1) << std::endl; // take 8 first digits
// Note the +1 here ^ (because of the dot)
return 0;
}
Output
0.1234567
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 have been trying to convert a double into string without the C++11 (ToString) but it only accepts the number of decimals to be 5 as default. How can I change that?
The command is:
string a = static_cast<ostringstream*>( &(ostringstream()<<digits) )->str();
but it keeps 5 decimals while I want to create a string which has all the decimals (e.g. 100)
I know that, that many decimals dont matter. This is one point of the exercise I was doing.
Any suggestions?
Thank you very much for your time
Cheers!
Use IO manipulators setprecision here on std::cout but works on stringstream:
// setprecision example from cplusplus.com
#include <iostream> // std::cout, std::fixed
#include <iomanip> // std::setprecision
int main () {
double f =3.14159;
std::cout << std::fixed << std::setprecision(9) << f << '\n';
return 0;
}
By the way, no double will have 100 meaningfull digit, it's 15 or 17, I forgot exactly how many.
EDIT: I forgot, if you can use C++11... You can (and should) use to_string
#include <string>
// ....
std::string f_str = std::to_string(f);
This worked for me finally
digits = 1.12345123451234;
char buff[100];
sprintf(buff, "%1.14f", digits);
string a(buff);
Thanks for checking it in any case
Cheers