5

我有一个用 C++ 编写的程序,它为数学计算生成 C 源代码。我注意到常量在生成的代码中占用了很多空间,并且正在寻找更紧凑的表示形式。

为了生成常量,我现在使用:

double v = ...
cfile << std::scientific << std::setprecision(std::numeric_limits<double>::digits10 + 1) << v;

我很确定这是一种无损表示,但它也非常臃肿。例如,零和一将表示为 0.00000000000000000e+00 和 1.0000000000000000e+00。和“0”。或“1”。携带同样多的信息。

有没有办法以更紧凑但仍无损的方式将常量打印到文件中?对于人类读者来说,它不需要看起来很好,只需在以纯 C 代码存在时进行编译(如果是 C99,我希望它也是有效的 C++)。如果它是可移植的,十六进制可能没问题。

std::fixed编辑:在代码片段中删除。

4

4 回答 4

10

您可以使用十六进制浮点(C 中 printf() 的格式说明符 %a);它被定义为保留所有精度位(C11,7.21.6.1p8,a,A说明符)。

cfile << std::hexfloat << v;

如果您的编译器/标准库不支持hexfloat,您可以使用 C99 %aprintf 说明符(这是等效的,如 C++11 表 88 中的第 22.4.2.2.2 节中所指定):

printf("%a", v);

例如,以下程序是有效的 C99:

#include <stdio.h>
int main() {
   double v = 0x1.8p+1;
   printf("%a\n", v);
}

您生成的源文件将不是有效的 C++11,因为荒谬的是 C++11 不支持十六进制浮点文字。然而,许多 C++11 编译器支持 C99 十六进制浮点文字作为扩展。

于 2013-03-01T11:41:22.273 回答
3

这不是表示、语言或标准库的问题,而是算法的问题。如果您有代码生成器,那么...为什么不将生成的代码更改为最佳(= 要求精度最短)表示?这就是你手工编写代码时所做的事情。

在假设的put_constant(double value)例程中,您可以检查您必须编写的值是什么

  • 是整数吗?不要用std::fixedand使代码膨胀set_precision,只需转换为整数并添加一个点。
  • 尝试使用默认设置将其转换为字符串,然后将其转换回double,如果没有任何更改,则默认(短)表示就足够了。
  • 使用您的实际实现将其转换为字符串,并检查其长度。如果它超过 N(见下文),则使用另一种表示,否则只需编写它。

当浮点数有很多位数时,一种可能的(短)表示是使用它们的内存表示。有了这个,你有一个相当固定的开销,长度永远不会改变,所以你应该只将它应用于非常长的数字。一个简单的例子来展示它是如何工作的:

#define USE_L2D __int64 ___tmp = 0;
#define L2D(x) (double&)(___tmp=x)

int main(int argc, char* argv[])
{
    // 2.2 = in memory it is 0x400199999999999A

    USE_L2D
    double f1 = L2D(0x400199999999999A);
    double f2 = 123456.1234567891234567;

    return 0;
}
于 2013-03-01T11:18:44.250 回答
1

首先,当你第一次说 std::scientific,然后时,你是在自相矛盾std::fixed。其次,你可能也不想要。默认格式通常设计为最好地做到这一点。默认格式没有名称,也没有操纵器,但是如果没有指定其他格式,则可以得到,并且可以使用以下方法设置(以防其他代码设置了不同的格式):

cfile.setf( std::ios_base::fmtflags(), std::ios_base::floatfield );

我建议使用这个。(当然,您仍然需要精确度。)

于 2013-03-01T11:24:00.480 回答
-4

我不确定您是否可以像这样无损地传递浮点数。浮点数必然是有损的。虽然它们可以精确地表示值的子集,但您不能包含所有有效数字 - 不同的硬件可能有不同的表示,因此您不能保证不会丢失信息。即使您可以将其全部传递,因为接收硬件可能无法表示该值。

不过,普通的 ofstream::operator<< 会根据需要打印出尽可能多的数字,因此实际上不需要使事情复杂化。

于 2013-03-01T11:18:08.863 回答