我有一个浮点,我想打印到正好N个空格。例如,在N=5的情况下。我想打印以下数字:
0.1 => 0.1
123.456789 => 123.5
-123.45678 => -123 (or -123.)
0.123456 => 0.123
123456.789 => 123456 (obviously, in this case, we cannot print less than 6 digits, if I can detect this, I can also print 12** to indicate the field is too wide.
我尝试过很多组合,包括以下几种:
// Leave 3 extra space: One for negative sign, one for zero, one for decimal
std::cout << std::setiosflags(std::ios::fixed)
<< std::setprecision(N - 3)
<< std::setw(N)
<< input;
但结果并不乐观。也许我错过了一些显而易见的东西?
这些样本输入的给定代码的输出是
0.10 // not bad
123.46 // Use 6 instead of 5 spaces
-123.46 // Use 7 instead of 5 spaces
0.12 // Under-use the spaces
123456.79 // Ok, I guess
使用Boost的精神。因果报应:
#include <boost/spirit/include/karma.hpp>
namespace karma = boost::spirit::karma;
double d = 12345.6;
// will print: 12345
std::cout << karma::format(
karma::maxwidth(5)[karma::double_], d
) << std::endl;
这将在任何情况下将您的输出宽度限制为CCD_ 1。如果您想发现数字被截断的情况(如您的例子中的123456.7(,只需提前执行适当的检查:
if (d < 1e6) {
// d == 12345 will print: 12345
std::cout << karma::format(
karma::maxwidth(5)[karma::double_], d
) << std::endl;
}
else {
// d == 123456 will print: 12***
std::cout << karma::format(
karma::left_align(5, '*')[
karma::maxwidth(2)[karma::double_]
], d
) << std::endl;
}
是的,如果你可能会问的话,Boost的Spirit。Karma是用标准C++功能编写的。
int main ()
{
const int N = 4;
double f = 123.456789;
// just use default floating-point notation to display N significant digits.
// no fixed or scientific notation work for your requirement.
// you can comment setf() line out if there is no one changing ios::floatfield.
cout.setf(0, ios::floatfield);
cout.precision(N);
cout << f << endl; // will print 123.5
}
[更新]我应该对提供的所有病例进行检测D
#include <iostream>
#include <math.h>
using namespace std;
void print_test(double number)
{
const int N = 5; // should be greater than 2
double maxIntPart = pow(10.0, number >= 0 ? N - 2 : N - 3);
double fractpart, intpart;
fractpart = modf(number , &intpart);
ios_base::fmtflags prevNotation = cout.setf(0, ios::floatfield); // use default floating-point notation
streamsize prevPrecicion = cout.precision();
if( abs(intpart) > maxIntPart )
{
intpart = ceil(number);
if( abs(intpart) < maxIntPart * 10 )
{
cout << intpart << endl;
}
else
{
while( abs(intpart) >= maxIntPart )
{
intpart /= 10;
}
cout << (intpart > 0 ? floor(intpart) : ceil(intpart)) << "**" << endl;
}
}
else
{
if ( number < 0 )
{
cout.precision(N - 3);
}
else if ( intpart == 0)
{
cout.precision(N - 2);
}
else
{
cout.precision(N - 1);
}
cout << number << endl;
}
cout.setf(prevNotation, ios::floatfield);
cout.precision(prevPrecicion);
}
int main ()
{
print_test(0.1); // 0.1
print_test(123.456789); // 123.5
print_test(-123.45678); // -123
print_test(0.123456); // 0.123
print_test(-0.123456); // -0.12
print_test(123456.789); // 123**
print_test(-123456.789); // -12**
}
您似乎想要打印N个字符,包括减号(如果有的话(和小数点。setprecision
只关心小数点后的位数。所以,一点数学可以得到你想要的:
#include <cmath>
// determine what precision we need
int precision = N - 1; // leave room for the decimal point
if (input < 0) --precision; // leave room for the minus sign
precision -= (1 + (int)log10(abs(input))); // how many digits before the decimal?
if (precision < 0) precision = 0; // don't go negative with precision
std::cout << std::setiosflags(std::ios::fixed)
<< std::setprecision(precision)
<< std::setw(N)
<< input;
我可能需要解释对数线:
precision -= (1 + (int)log10(abs(input))); // how many digits before the decimal?
- 0-9之间的任何字符都需要一位数字才能打印
- 0-9的log10将给出一个小于1的数字,该数字将截断为int
0
- 10-99之间的任何数字都需要两位数才能打印出来
- 10-99的log10将给出一个至少为1但小于2的数字-截断为int
1
- 所以。。。log10(输入(加1是它打印的位数
iostream精度/宽度标志不能很好地满足您的要求-例如,precision
计数有效数字而不是字符位置,4个请求0.123456映射到0.1234而不是您请求的0.123(您希望0.0012346为"0.00"吗?(。无论如何,要使用精度,您需要根据值更改参数按照以下方式编写自己的函数可能更容易。。。
最简单的方法是以额外的精度将值写入字符串流,然后从左到右扫描(记录是否找到"."(,直到到达要截断的点,然后从右到左扫描以删除尾随的0,或者如果之前没有遇到".",则替换"**"。
否则,您可以实现自己的双ASCII转换,可能使用像linux的<ieee754.h>
这样的头来提供具有float
和double
类型的位字段的union
;否则使用您选择的数学运算。
丑陋,但也许你想要:
if(input < pow(10,N+1)) {
ostringstream sout;
sout << input;
cout << setw(N) << sout.str().substr(0,N);
} else cout << (int)input;