I want to print to screen some numbers with at most 4 digits after decimal point using iomanip
.
I've learned that in default mode setprecision
counts not only the digits after decimal point but also the digits in the integer part. This code
#include <iostream>
#include <iomanip>
int main () {
double numbers[] = {3.141516, 1.01, 200.78901, 0.12345};
int len = sizeof(numbers) / sizeof(numbers[0]);
std::cout << std::setprecision(4);
for (int i = 0; i < len; ++i) {
std::cout << numbers[i] << '\n';
}
return 0;
}
outputs:
3.142
1.01
200.8
0.1235
But what I want is: (at most 4 digits after decimal point without trailing zeros)
3.1415
1.01
200.789
0.1235
Is iomanip
capable of doing this? Without using other tricks (like round
)?
EDIT
It seems that I haven't made it clear enough. My question is iomanip
specific
All I want to know is whether iomanip
is capable of doing things I've described because iomanip
is said to be the standard library for input/output manipulators. The posted question is
Is
iomanip
capable of doing this?
It's more like "is it supported" rather than "give me any solution".
I have searched it again, looked up iomanip
references hoping for a clean and compact way to format floating numbers for at most n
digits, using unnecessary libraries as little as possible.
And there seems to be no standard way to achieve this.
One (ugly) option to obtain OP's desired output is to represent the number with the wanted maximum precision and then just remove the unwanted zeroes:
#include <iostream>
#include <iomanip>
#include <sstream>
#include <vector>
int main()
{
std::vector<double> numbers {
3.141516, 1.01, 200.78901, 0.12345, 9.99999
};
for (auto x : numbers)
{
// "print" the number
std::stringstream ss;
ss << std::fixed << std::setprecision(4) << x;
// remove the unwanted zeroes
std::string result{ss.str()};
while (result.back() == '0')
result.pop_back();
// remove the separator if needed
if (result.back() == '.')
result.pop_back();
std::cout << result << '\n';
}
std::cout << "\nJustified:\n";
for (auto x : numbers)
{
// "print" the number
std::stringstream ss;
ss << std::fixed << std::setprecision(4) << std::setw(15) << x;
// remove the unwanted zeroes
std::string result{ss.str()};
auto it = result.rbegin();
while (*it == '0')
*it++ = ' ';
// remove the separator if needed
if (*it == '.')
*it = ' ';
std::cout << result << '\n';
}
}
Live example: https://ideone.com/8zP17O
So:
std::fixedfield
mode, std::setprecision
sets the maximum number of significant figures , not decimal places; std::fixed
it means exact number of decimal places; %.Nf
printf format string! (up to N decimal places) I've just thrown together a little fake I/O manipulator that can get the behaviour we both want. It's not terribly performant, but it does the job:
#include <iostream>
#include <iomanip>
#include <string>
#include <sstream>
#include <cstdio>
struct sprintf_wrapper
{
sprintf_wrapper(std::string fmt_str)
: _fmt_str(std::move(fmt_str))
{}
struct proxy
{
proxy(const sprintf_wrapper& wrapper, std::ostream& os)
: _wrapper(wrapper)
, _os(os)
{}
std::ostream& Resolve(const double value) const
{
// First find out how many characters we're going to need
const int len = std::snprintf(nullptr, 0, _wrapper._fmt_str.c_str(), value);
if (len < 0)
{
_os.setstate(std::ios::failbit);
return _os;
}
// Then allocate a buffer
std::string result;
result.resize(len);
// Actually serialise the value according to the format string
if (std::sprintf(result.data(), _wrapper._fmt_str.c_str(), value) < 0)
{
_os.setstate(std::ios::failbit);
return _os;
}
// Stream it out
_os.write(result.data(), result.size());
return _os;
}
friend std::ostream& operator<<(const proxy& obj, const double val)
{
return obj.Resolve(val);
}
private:
const sprintf_wrapper& _wrapper;
std::ostream& _os;
};
friend proxy operator<<(std::ostream& os, const sprintf_wrapper& obj)
{
return proxy(obj, os);
}
private:
std::string _fmt_str;
};
inline auto sprintf_f(size_t n, const bool showpos = false)
{
std::stringstream fmt;
fmt << '%';
if (showpos) fmt << '+';
fmt << '.' << n << 'f';
return sprintf_wrapper(fmt.str());
}
int main()
{
std::cout << sprintf_f(2) << 4.123456789 << '\n';
std::cout << sprintf_f(3) << 4.123456789 << '\n';
std::cout << sprintf_f(4) << 4.123456789 << '\n';
std::cout << sprintf_f(5) << 4.123456789 << '\n';
std::cout << sprintf_f(6) << 4.123456789 << '\n';
}
Use a combination of std::fixed
and std::setprecision
.
#include <iomanip>
#include <iostream>
int main() {
double d = 311.3456;
std::cout << std::fixed;
std::cout << std::setprecision(4);
std::cout << d << std::endl;
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.