仅使用标准C++将任何浮点值精确打印到N个空格



我有一个浮点,我想打印到正好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>这样的头来提供具有floatdouble类型的位字段的union;否则使用您选择的数学运算。

丑陋,但也许你想要:

if(input < pow(10,N+1)) {
  ostringstream sout;
  sout << input;
  cout << setw(N) << sout.str().substr(0,N);
} else cout << (int)input; 

相关内容

  • 没有找到相关文章

最新更新