using stringstream to print a rounded floating point number - c++

i have floating point variables "lmin" and "lmax". i wish to display only 4 significant digits. i am currently using something i have found online of the form ...
string textout;
stringstream ss;
ss << lmin;
textout = ss.str();
output(-0.5, -0.875, textout);
ss.str("");
ss << lmax;
textout = ss.str();
output(0.2, -0.875, textout);
where "output" is simply a function i wrote to parse the string and print it to the screen. the important point, is how do i print only a ROUNDED version of lmin and lmax to ss?

Use std::setprecision to specify the number of digits after the decimal point.
#include <sstream>
#include <iostream>
#include <iomanip>
int main()
{
double d = 12.3456789;
std::stringstream ss;
ss << std::fixed << std::setprecision( 4 ) << d;
std::cout << ss.str() << std::endl;
}
Output:
12.3457

Simply use ss.precision( 4 ) or ss << std::setprecision( 4 ) before inserting the output.

Related

How to remove trailing zeros with scientific notation when convert double to string?

Live On Coliru
FormatFloat
I try to implement one conversion of Golang strconv.FormatFloat() in C++.
#include <sstream>
#include <iostream>
#include <string>
#include <iomanip>
using namespace std;
std::string convert_str(double d)
{
std::stringstream ss;
if (d >= 0.0001)
{
ss << std::fixed << std::setprecision(4); // I know the precision, so this is fine
ss << d;
return ss.str();
}
else
{
ss << std::scientific;
ss << d;
return ss.str();
}
}
int main()
{
std::cout << convert_str(0.002) << std::endl; // 0.0020
std::cout << convert_str(0.00001234560000) << std::endl; // 1.234560e-05
std::cout << convert_str(0.000012) << std::endl; // 1.200000e-05
return 0;
}
Output:
0.0020
1.234560e-05 // should be 1.23456e-05
1.200000e-05 // should be 1.2e-05
Question> How can I setup the output modifier so that the trailing zero doesn't show up?
strconv.FormatFloat(num, 'e', -1, 64)
The special precision value (-1) is used for the smallest number of
digits necessary such that ParseFloat() will return f exactly.
At the risk of being heavily downvoted criticised for posting a C answer to a C++ question ... you can use the %lg format specifier in a call to sprintf.
From cpprefernce:
Unless alternative representation is requested the trailing zeros are
removed, also the decimal point character is removed if no fractional
part is left.
So, if you only want to remove the trailing zeros when using scientific notation, you can change your convert_str function to something like the following:
std::string convert_str(double d)
{
if (d >= 0.0001) {
std::stringstream ss;
ss << std::fixed << std::setprecision(4); // I know the precision, so this is fine
ss << d;
return ss.str();
}
else {
char cb[64];
sprintf(cb, "%lg", d);
return cb;
}
}
For the three test cases in your code, this will give:
0.0020
1.23456e-05
1.2e-05
From C++20 and later, the std::format class may offer a more modern alternative; however, I'm not (yet) fully "up to speed" with that, so I cannot present a solution using it. Others may want to do so.
Yes, std::scientific don't remove trailing zeros from scientific notation. The good news, for your specific case, is that cout already format values below 0.0001 using scientific notation, and removing trailing zeros. So you can let your code like this:
#include <sstream>
#include <iostream>
#include <string>
#include <iomanip>
using namespace std;
std::string convert_str(double d)
{
std::stringstream ss;
if (d >= 0.0001)
{
ss << std::fixed << std::setprecision(4); // I know the precision, so this is fine
ss << d;
return ss.str();
}
else
{
ss << d;
return ss.str();
}
}
int main()
{
std::cout << convert_str(0.002) << std::endl; // 0.0020
std::cout << convert_str(0.00001234560000) << std::endl; // 1.23456e-05
std::cout << convert_str(0.000012) << std::endl; // 1.2e-05
return 0;
}
The wanted output can be generated with a combination of the std::setprecision and std::defaultfloat manipulators:
std::cout << std::setprecision(16) << std::defaultfloat
<< 0.002 << '\n'
<< 0.00001234560000 << '\n'
<< 0.000012 << '\n';
Live at: https://godbolt.org/z/67fWa1seo

Get longer calculation-output of log() in C++

I need to get a more precise output of the math function log().
I want to obtain the 2. and 10th digit of the number.
My test code looks like this:
#include "string"
#include <sstream>
double temp_number = log(10.0);
std::ostringstream strs;
strs << temp_number;
std::string str = strs.str();
std::cout << str << "\n";
I'm casting the double to string because I don't know how to obtain numbers by index in double's. Anyhow, when casting to string and even if I check the output before with cout the calculation get's rounded to 6 digits which is clearly not precise enough.
Any suggestions?
Correct way is:
#include "string"
#include <sstream>
#include <iomanip> // std::setprecision
double temp_number = log(10.0);
std::ostringstream strs;
strs << std::setprecision(15) << temp_number;
std::string str = strs.str();
std::cout << str << "\n";
Usind std::setprecision(15) helps to get the correct values

std::hex and std::setw not working with some characters

What I'm trying to do is converting a string's bytes into hexadecimal format.
Based on this answer (and many others consistent) I've tried the code:
#include <sstream>
#include <iomanip>
#include <iostream>
int main ()
{
std::string inputText = u8"A7°";
std::stringstream ss;
// print every char of the string as hex on 2 values
for (unsigned int i = 0; i < inputText.size (); ++i)
{
ss << std::hex << std::setfill ('0') << std::setw (2) << (int) inputText[i];
}
std::cout << ss.str() << std::endl;
}
but with some characters coded in UTF 8 it does't work.
For Instance, in strings containing the degrees symbol ( ° ) coded in UTF8, the result is: ffffffc2ffffffb0 instead of c2b0.
Now I would expect the algorithm to work on individual bytes regardless of their contents and furthermore the result seems to ignore the setw(2) parameter.
Why does I get such a result?
(run test program here)
As Pete Becker already hinted in a comment, converting a negative value to a larger integer fills the higher bits with '1'. The solution is to first cast the char to unsigned char before casting it to int:
#include <string>
#include <iostream>
#include <iomanip>
int main()
{
std::string inputText = "-12°C";
// print every char of the string as hex on 2 values
for (unsigned int i = 0; i < inputText.size(); ++i)
{
std::cout << std::hex << std::setfill('0')
<< std::setw(2) << (int)(unsigned char)inputText[i];
}
}
setw sets the minimal width, it does not truncate longer values.

How do you prepend to std::stringstream?

std::stringstream ss;
int number = 0x12345678;
ss << std::hex << number;
cout << ss.str();
This will produce 12345678
I want to make it as 0x12345678. How can I prepend 0x in front of ss.str()?
The probably simplest way to do this is to change the formatting of the stringstream ss: Make it automatically prepend the number base with std::showbase:
#include <sstream>
#include <iostream>
int main()
{
std::stringstream ss;
int number = 0x12345678;
ss << std::showbase << std::hex << number; // prepends the 0x automagically
std::cout << ss.rdbuf(); // empties ss
}
Note that I changed the output from cout << ss.str() to cout << ss.rdbuf(). This modifies the stream ss (it is empty afterwards), but requires no copy as in the OP's example.
Once you've put the number into the stringstream, there's no simple way I know of to prepend the 0x in this stringstream. You could then however print it before printing the contents of the stream to cout:
std::cout << "0x" << ss.rdbuf();

Formatting n significant digits in C++ without scientific notation

I want to format a floating point value to n significant digits but never using scientific notation (even if it would be shorter).
The format specification %f doesn't deal in significant digits, and %g will sometimes give me scientific notation (which is inappropriate for my use).
I want values in the form "123", "12.3", "1.23" or "0.000000123".
Is there an elegant way to do this using C++ or boost?
The best way I know (and use it in my own code) is
#include <string>
#include <math.h>
#include <sstream>
#include <iomanip>
int round(double number)
{
return (number >= 0) ? (int)(number + 0.5) : (int)(number - 0.5);
}
std::string format(double f, int n)
{
if (f == 0) {
return "0";
}
int d = (int)::ceil(::log10(f < 0 ? -f : f)); /*digits before decimal point*/
double order = ::pow(10., n - d);
std::stringstream ss;
ss << std::fixed << std::setprecision(std::max(n - d, 0)) << round(f * order) / order;
return ss.str();
}
c++11 has std::round so you won't need my version of with a new compiler.
The trick I'm exploiting here is to get the precision you want by taking the base 10 log to count the number of digits before the decimal and subtracting this from the precision you want.
It satisfies #Mats Petersson's requirement too, so will work in all cases.
The bit I don't like is the initial check for zero (so the log function doesn't blow up). Suggestions for improvement / direct editing of this answer most welcome.
std::fixed and std::setprecision (and <iomanip> in general) are your friends.
std::cout << 0.000000123 << '\n';
prints 1.23e-07 and
std::cout << std::setprecision(15) << std::fixed << 0.000000123 << '\n';
prints 0.000000123000000
Just remember that floating-point numbers have limited precision, so
std::cout << std::fixed << 123456789012345678901234567890.0 << '\n';
will print 123456789012345677877719597056.000000 (probably not what you want)
I think you'll have to remove trailing zeros by yourself :
string trimString(string str)
{
string::size_type s;
for(s=str.length()-1; s>0; --s)
{
if(str[s] == '0') str.erase(s,1);
else break;
}
if(str[s] == '.') str.erase(s,1);
return str;
}
Usage :
double num = 0.000000123;
stringstream ss;
ss << num;
ss.str("");
ss << std::setprecision(15) << std::fixed << num; // outputs 0.000000123000000
string str;
ss >> str;
str = trimString(str);
cout << str << endl; // outputs 0.000000123
Put together :
string format(int prec, double d) {
stringstream ss;
ss << d;
ss.str("");
ss << std::setprecision(prec) << std::fixed << d;
string str;
ss >> str;
string::size_type s;
for(s=str.length() - 1; s > 0; --s)
{
if(str[s] == '0') str.erase(s,1);
else break;
}
if(str[s] == '.') str.erase(s,1);
return str;
}
Usage :
double num = 0.000000123;
cout << format(15, num) << std::endl;
If someone knows a better way ...