繁体   English   中英

C / C ++中浮点常数的紧凑无损表示

[英]Compact lossless representation of floating point constants in C/C++

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

要生成常量,我现在使用:

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

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

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

编辑:删除了代码片段中的std::fixed

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

cfile << std::hexfloat << v;

如果你的编译器/标准库不支持hexfloat ,你可以使用C99 %a printf说明符(这是等效的,如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十六进制浮点文字作为扩展。

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

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

  • 它是整数吗? 不要使用std::fixedset_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;
}

首先,当你第一次说std::scientific ,然后std::fixed时,你就是自相矛盾的。 第二,你可能也不想要。 默认格式通常旨在实现此目的。 默认格式没有名称,也没有操纵器,但如果没有指定其他格式,则可以获得,并且可以设置(如果其他代码设置了不同的格式),使用:

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

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

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

但是,普通的ofstream :: operator <<会打印出所需的数字,因此实际上并不需要使问题复杂化。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM