【问题标题】:Print a max of 4 decimals最多打印 4 位小数
【发布时间】:2017-05-04 22:29:09
【问题描述】:

我正在尝试在 C++ 中打印小数点后最多 4 位数字(使用流)。因此,如果数字不需要小数点后 4 位,我希望它只使用它实际需要的小数位数。

例子:

1.12345    -> 1.1234
1.0        -> 1
1.12       -> 1.12
1.12345789 -> 1.1234
123.123    -> 123.123
123.123456 -> 123.1234

我尝试了std::setprecision(4),但它设置了有效位数并在测试用例中失败:

123.123456 gives 123.1

我也尝试将std::fixedstd::setprecision(4) 一起提供,但即使不需要,也会给出固定的小数位数:

1.0 gives 1.0000

似乎std::defaultfloat 是我需要的,不是固定的也不是指数的。但它似乎没有适当地打印小数点后的位数,并且只有有效数字的选项。

【问题讨论】:

  • 这需要自定义代码,处理要打印的值的 BCD 或字符串表示形式。请记住,因为浮点数的底层表示是二进制的,所以不一定有(比如)123.123 的精确二进制表示。如果您显示了足够多的小数位,double x = 123.123; cout << x 之类的内容可能会输出123.1230000001 之类的内容。因此,我建议编写一个函数,将双精度转换为具有四个小数位的字符串,然后在返回字符串之前删除小数位后的所有尾随零。
  • 您的示例与您的问题描述不符。查看这些示例,您更像是不希望超过 4 个小数,并且没有任何尾随零。这肯定与 4 位小数不一样。此外,正如 Simon 所指出的,鉴于 IEEE 浮点值表示的性质,您必须为短语 “需要一个数字” 的含义提供更好的规范。
  • 所以你希望它只打印四位数字,除非它不打印四位数字?
  • 我将其表述为“在小数点后最多打印 4 位数字,省略尾随零”。

标签: c++ printing cout


【解决方案1】:

我们可以使用std::stringstreamstd::string 来做到这一点。我们将double 传递给格式化它的流,就像我们将它发送给cout 一样。然后我们检查从流中得到的字符串,看是否有尾随零。如果有我们摆脱它们。一旦我们这样做了,我们就会检查我们是否只剩下一个小数点,如果是,那么我们也可以摆脱它。你可以使用这样的东西:

int main()
{
    double values[] = { 1.12345, 1.0, 1.12, 1.12345789, 123.123, 123.123456, 123456789, 123.001 };
    std::vector<std::string> converted;
    for (auto e : values)
    {
        std::stringstream ss;
        ss << std::fixed << std::setprecision(4) << e;
        std::string value(ss.str());
        if (value.find(".") != std::string::npos)
        {
            // erase trailing zeros
            while (value.back() == '0')
                value.erase(value.end() - 1);
            // if we are left with a . at the end then get rid of it
            if (value.back() == '.')
                value.erase(value.end() - 1);
            converted.push_back(value);
        }
        else
            converted.push_back(value);
    }
    for (const auto& e : converted)
        std::cout << e << "\n";
}

当做成running example 时会给出

1.1235
1
1.12
1.1235
123.123
123.1235
123456789
123.001

【讨论】:

    【解决方案2】:

    使用来自here 的答案以及自定义逻辑来删除零和点:

    #include <iostream>
    #include <iomanip>
    #include <sstream>
    #include <string>
    #include <vector>
    #include <iterator>
    #include <algorithm>
    
    std::string remove_zeros(std::string numberstring)
    {
        auto it = numberstring.end() - 1;
        while(*it == '0') {
            numberstring.erase(it);
            it = numberstring.end() - 1;
        }
        if(*it == '.') numberstring.erase(it);
        return numberstring;
    }
    
    std::string convert(float number)
    {
        std::stringstream ss{};
        ss << std::setprecision(4) << std::fixed << std::showpoint << number;
        std::string numberstring{ss.str()};
        return remove_zeros(numberstring);
    }
    
    int main()
    {
        const float values[]{1.12345, 1.0, 1.12, 1.12345789, 147323.123, 123.123456};
        for(auto i : values)
            std::cout << convert(i) << '\n';
    }
    

    产生:

    1.1235
    1
    1.12
    1.1235
    147323.125
    123.1235
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-03-26
      • 2013-02-06
      • 2015-12-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多