C++ 仅使用标准C++;要将任何浮点打印到正好N个空格

C++ 仅使用标准C++;要将任何浮点打印到正好N个空格,c++,formatting,stream,C++,Formatting,Stream,我有一个浮点数,我想打印到正好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

我有一个浮点数,我想打印到正好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;
int main()
{
常数int N=4;
双f=123.456789;
//只需使用默认的浮点表示法来显示N个有效数字。
//没有固定的或科学的符号工作为您的要求。
//如果没有人更改ios::floatfield,则可以将setf()行注释掉。
cout.setf(0,ios::floatfield);
计算精度(N);
cout(最大部分)
{
intpart=ceil(编号);
if(abs(intpart)iostream精度/宽度标志不能很好地满足您的要求-例如,
precision
计算有效数字而不是字符位置,4个请求0.123456映射到0.1234而不是您请求的0.123(您是否希望0.00123456为“0.00”?)。无论如何,要使用精度,您需要根据值更改参数。编写自己的函数可能更容易,如下所示

最简单的方法是以更高的精度将值写入stringstream,然后从左向右扫描(记录是否找到“.”),直到到达要截断的点,然后从右向左扫描以删除尾随的0,或者如果之前没有遇到“.”则替换“**”


否则,您可以实现自己的双精度到ASCII转换,可能使用类似linux的
头来提供一个
联合
,在
浮点数
双精度
类型上提供位字段;否则使用您选择的数学运算。

丑陋,但您可能想要:

if(input < pow(10,N+1)) {
  ostringstream sout;
  sout << input;
  cout << setw(N) << sout.str().substr(0,N);
} else cout << (int)input; 
#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;
if(输入sout您似乎想要打印N个字符-包括减号(如果有的话)和小数点。
setprecision
只关心小数点后的位数。因此,一点数学可以得到您想要的:

if(input < pow(10,N+1)) {
  ostringstream sout;
  sout << input;
  cout << setw(N) << sout.str().substr(0,N);
} else cout << (int)input; 
#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;
  • 0-9之间的任何内容都需要一位数字才能打印
  • 0-9的log10将给出一个小于1的数字,该数字将截断为int
    0
  • 10-99之间的任何内容都需要两位数字才能打印
  • 10-99的log10给出的数字至少为1,但小于2-截断为int
    1
  • 所以…log10(输入)加1是它打印的数字数

使用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;

是的,如果你可能会问,Boost的精神。卡尔玛是用标准的C++特性编写的。< /P>结果,结果如何不好?技术上,代码>代码123456.789 >代码>可以打印在5个空间:<代码> 123e3 < /代码>对于给定的输入,上面提供的输出不符合预期:0.1、123.5、0.1235、1.23 5e+05。(GCC 4.5.2)好吧,我还没有看过它真的-觉得最好是让Dat Chu自己至少有一个裂缝,因为他意识到他不能只使用

精度
/
setw
/
填充
-但是做得很好:-)+1.这类事情似乎很接近,但你可以得到“123”,而不是“123”,并且需要更复杂一点来处理负片。您的解决方案确实非常优雅。我在我的项目中添加了一个CMake选项,如果用户愿意,它将使用Boost.Karma而不是我的解决方案。您是否可以更新您的解决方案以包括Karma::right_align(5),以便输出始终正好是5个字符?如下所述:
precision -= (1 + (int)log10(abs(input))); // how many digits before the decimal?
#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;
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;
}