在不强制固定宽度的情况下删除浮标上的科学记数法

时间:2012-06-20 13:17:46

标签: c++

我正在使用ofstream输出浮动CSV。 99%的浮点数的精确度为1-2位小数,因此只需使用fileOut.precision(3)就足以强制使用正确的精度。

一次又一次浮动将具有极低的值,因此将以科学记数法1e-007输出。在这种情况下,我最好是0

这里有很多答案建议使用类似于fileOut.setf(std::ios::fixed, std::ios::floatfield);的内容来阻止这种情况,但这会使每个字段输出为0.000,无论它是否需要那么多数字。

我希望所有花车能够正常运行并且不显示科学记数法。

无论如何要做到这一点,还是我必须创建一个简单的函数来检查一个数字是否低于0.001,如果这样设置为0?

更新

我现在使用以下代码来包装任何浮点数,它不是理想的但是有效。

float _RoundToZero(float in, int precision = 2)
{
  return in <= (1 / powf(10,precision)) ? 0.0 : in;
}

2 个答案:

答案 0 :(得分:0)

考虑将值乘以100打印为整数(舍入精度)。这样,虽然有时你会得到尾随的零,你将永远不必打印小数位,这将为每个值浪费1个字符。

或者,以二进制形式写入float。由于所有浮点数都具有相同的大小(4个字节),因此您可以保留原始数据的所有精度,而不必担心尾随零,您的文件大小非常可预测,并且您不必浪费空间来区分值。 100个值需要400个字节。在文本格式中,值至少需要2个字节(数字+字段分隔符)和格式允许的最大值(包括小数点一个)加上分隔符。在这种格式中,4个字节可以获得2个有效精度数字,而不是5或6个浮点数。

答案 1 :(得分:-1)

抱歉,使用iostream printf无法实现。唯一的选择是:

  • 实现您自己的浮点格式化例程以进行正确的舍入。
  • 将float格式化为字符串并修剪零。
  • 如果该值小于阈值,则将其四舍五入为零。

第一个是复杂的,最后一个是不准确的(在二进制浮点数中不能完全代表10 -n )。

所有这些都可以通过覆盖numput facet来实现,这将允许您像以前一样保持格式化代码。

以下是最后一个选项的实现:

#include <iostream>
#include <locale>
#include <math.h>
using namespace std;

class my_put : public std::num_put<char> {
    iter_type do_put (iter_type out, ios_base& str, char_type fill, double val) const
    {
        streamsize prec = str.precision();
        if((str.flags() & ios_base::floatfield) == ios_base::fixed && fabs(val)*2 <= pow(10.0, -(int)prec))
            str.precision(0);
        out = std::num_put<char>::do_put(out, str, fill, val);
        str.precision(prec);
        return out;
    }
};

int main()
{
    double a[] = {123, 0, 0.001, 0.0001 };
    cout.imbue(locale(cout.getloc(), new my_put));
    cout.precision(3);
    cout.setf(ios_base::fixed, ios_base::floatfield);
    for(int i = 0; i < 4; ++i)
        cout << a[i] << '\n';
}

请在此处查看输出:http://ideone.com/qaV0w

请注意,边界情况(0.0005)的正确性取决于下划线浮点格式和实现。