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和1可以表示为0.0000000000000000e+00和1.00000000000000e +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("%an", v);
}
生成的源文件在c++ 11中是无效的,因为c++ 11不支持十六进制浮点量。然而,许多c++ 11编译器支持C99十六进制浮点量作为扩展。
这不是表示、语言或标准库的问题,而是算法的问题。如果你有一个代码生成器,那么…为什么不修改生成的代码,使其成为最好的(=最短的精度)表示形式呢?当你手工写代码时,你就会这么做。
在假设的put_constant(double value)
例程中,您可以检查必须写入的值:
- 是整数吗?不要用
std::fixed
和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;
}
首先,当你第一次说std::scientific
,然后是std::fixed
。其次,你可能两者都不想要。默认格式为设计得最好。默认格式不需要有一个名字,没有一个操纵者,但如果没有其他,你得到的是什么格式已指定,并可设置(以防其他代码设置了不同的格式)使用:
cfile.setf( std::ios_base::fmtflags(), std::ios_base::floatfield );
我建议使用这个。(你仍然需要精确的课程。)
我不确定你可以像这样无损地传递浮点数。浮点数必然是有损的。虽然它们可以精确地表示值的子集,但您不能包括所有有效数字-不同的硬件可能有不同的表示,因此您不能保证不丢失信息。即使您可以将其全部传递,因为接收硬件也可能无法表示该值。
普通的ofstream::operator<<可以根据需要打印出尽可能多的数字,因此没有必要使问题复杂化。
- 表示"accepting anything for this template argument" C++概念的通配符
- 如何将ampl中的集合表示为c++中的向量
- std::is_base_of表示ctor编译错误
- 输入中的字符串数未知(以字母表示)
- 我可以信任表示整数的浮点或双精度来保持精度吗
- c++模板来表示多项式
- 询问在设计我的手臂模拟器功能表示格式1
- CMakeLists.txt中的命名空间表示法
- C++射线示踪剂ppm表示没有足够的数据来显示图像
- 如何计算Big-O表示法中的平均渐近运行时间
- 我应该如何表示我拥有的连续元素序列?
- 在C++中,使用带有 std::optional 参数的函数<T>来表示可选参数是否有意义?
- 在 std::无符号字符的向量处存储 int 的十六进制表示形式
- 表示类模板C++空类型
- 具有所表示类的相同构造函数签名的代理类模板
- 嵌套在循环中的两个循环的 big-O 表示法
- 具有引用成员的结构是否具有唯一的对象表示形式
- 使用 int 表示浮点除法 C++
- Geeksforgeeks C 程序故障排除:IEE 754 表示法为十进制
- 如何知道n!是否可以表示为三个连续数字的乘法?