【问题标题】:double to string conversion with fixed width固定宽度的双精度字符串转换
【发布时间】:2014-07-21 04:27:45
【问题描述】:

我想将double 值打印成不超过 8 个字符的字符串。打印的数字应该有尽可能多的数字,例如

5.259675
48920568
8.514e-6
-9.4e-12

我尝试了 C++ iostreams 和 printf-style,但都没有以我希望的方式尊重提供的大小:

cout << setw(8) <<  1.0 / 17777.0 << endl;
printf( "%8g\n", 1.0 / 17777.0 );

给予:

5.62525e-005
5.62525e-005

我知道我可以指定一个精度,但我必须在这里提供一个非常小的精度,以涵盖最坏的情况。任何想法如何在不牺牲太多精度的情况下强制执行精确的字段宽度?我需要这个来打印矩阵。我真的必须想出自己的转换函数吗?

5 年前有人问过类似的问题:Convert double to String with fixed width,但没有令人满意的答案。我当然希望在此期间取得一些进展。

【问题讨论】:

  • 你试过boost::format吗?
  • 不确定我是否理解。如果双精度值恰好是 100000000 怎么办?输出应该是“99999999”吗?
  • C++ 的所有新特性都与此无关。这不是大多数人认为的“进步”。
  • @ChristianHackl:您是否错过了使用科学计数法的示例输出?
  • @BenVoigt:是的,我明白了。我误解了这个问题,对不起。

标签: c++ formatting


【解决方案1】:

实际上,这似乎并不太难,尽管您不能在单个函数调用中做到这一点。指数使用的字符位置的数量真的很容易预测:

const char* format;
if (value > 0) {
    if (value < 10e-100) format = "%.1e";
    else if (value < 10e-10) format = "%.2e";
    else if (value < 1e-5) format = "%.3e";
}

等等。

只有定义 printf 行为的 C 标准坚持要求指数至少有两位数,所以它在那里浪费了一些。见c++ how to get "one digit exponent" with printf

结合这些修复程序将使代码相当复杂,尽管仍然不如自己进行转换那么糟糕。

【讨论】:

  • 等等是我害怕的部分。我需要对大量数据做同样的事情。计算- 是否为负数。检查是否要使用 %e%f。但也许你是对的,这是最不麻烦的解决方案。谢谢。
【解决方案2】:

如果您想转换为固定的十进制数(例如,去掉 +/-"E" 部分),那么它会更容易完成:

#include <stdio.h>
#include <cstring>     // strcpy
#include <iostream>     // std::cout, std::fixed
#include <iomanip>      // std::setprecision
#include <new>

char *ToDecimal(double val, int maxChars) 
{
    std::ostringstream buffer;
    buffer << std::fixed << std::setprecision(maxChars-2) << val;
    std::string result = buffer.str();

    size_t i = result.find_last_not_of('\0');
    if (i > maxChars) i = maxChars;
    if (result[i] != '.') ++i;
    result.erase(i);

    char *doubleStr = new char[result.length() + 1];
    strcpy(doubleStr, (const char*)result.c_str());

    return doubleStr;
}

int main()
{
    std::cout << ToDecimal(1.26743237e+015, 8) << std::endl;
    std::cout << ToDecimal(-1.0, 8) << std::endl;
    std::cout << ToDecimal(3.40282347e+38, 8) << std::endl;
    std::cout << ToDecimal(1.17549435e-38, 8) << std::endl;
    std::cout << ToDecimal(-1E4, 8) << std::endl;
    std::cout << ToDecimal(12.78e-2, 8) << std::endl;
}

输出:

12674323
-1
34028234
0.000000
-10000
0.127800

【讨论】:

  • 谢谢,但我认为这没有任何用处,请看第一行输出。结果是完全错误的。当我说我想要一个由 8 个字符组成的输出时,我的意思是我想要在某种程度上类似于输入的输出。
  • @pentadecagon 是的,对于最多 8 个字符的示例,您的数字不能大于 99999999(或 9.999999)或小于 -9999999(或 -0.00001)。很抱歉,这对你不起作用。
猜你喜欢
  • 2010-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-11
  • 1970-01-01
相关资源
最近更新 更多