C printf的最大数值信息密度
我的用例是将数字写入一个JSON文档,在这个文档中,大小最小化比非常小/非常大的数字的精度更重要。这些数字通常表示毫秒或米等常用单位,通常在[0.0011000]范围内 基本上我想设置一个最大字符长度。例如,如果限制为五个字符,则:C printf的最大数值信息密度,c,json,number-formatting,C,Json,Number Formatting,我的用例是将数字写入一个JSON文档,在这个文档中,大小最小化比非常小/非常大的数字的精度更重要。这些数字通常表示毫秒或米等常用单位,通常在[0.0011000]范围内 基本上我想设置一个最大字符长度。例如,如果限制为五个字符,则: from to 1234567 123e4 12345.6 12346 1234.56 1235 123.456 123.5 12.3456 12.35 1.23456 1.235 1.23450 1.235 1.23400
from to
1234567 123e4
12345.6 12346
1234.56 1235
123.456 123.5
12.3456 12.35
1.23456 1.235
1.23450 1.235
1.23400 1.234
1.23000 1.23
1.20000 1.2
1.00000 1
0.11111 0.111
0.01111 0.011
0.00111 0.001
0.00011 11e-4
0.00001 1e-5
0.11111 0.111
0.01111 0.011
0.00111 0.001
0.00011 11e-4
0.00001 1e-5
这个测试用例似乎在一个长度约束中传递了最多的信息
当数字提升到范围[-99999]之外的幂时,它确实会失败,并且该范围将根据所施加的限制而变化。在这些罕见的情况下,可能这里的失败只是为了编写更长的字符串
这是一个理想的解决方案,尽管如果另一个解决方案比较接近,我可以不亲自实现它,可能是截断而不是舍入,并且不利用科学/指数表示法
编辑以下是printf
与%.3f
,%.3g
,%.4g
通过比较产生的内容():
对于将特定范围内的数字打包为最小无符号整数: 1) 减去可能的最小值。例如,如果您的数字可能在0.001到100000之间,并且特定的数字是123.456,则减去0.001得到123.455 2) 除以你关心的精度。例如,如果您关心千分之一,则除以0.001。在这种情况下,数字123.455变为123455 完成此操作并获得最小宽度的无符号整数后,将其转换为十六进制数字(或者可能是“基32位”)。对于上面的示例,0.001将变为0x00000000,123.456将变为0x0001E23F,100000将变为0x05F5E0FF 如果需要“可变精度”,可以添加第三步,将无符号整数值拆分为“值和移位计数”形式。例如:
shift_count = 0;
while(value > 0xFFF) {
value = value >> 1;
shift_count++;
}
然后,您可以使用类似于
value=(value的东西进行连接。似乎您必须编写自己的转换例程。库函数可能会有所帮助
但是我会简单地使用%.3g
或%.4g
格式,去掉指数前多余的加号和前导零,就到此为止。这主要会留下一些可以优化的小数点。因为您非常关心JSON响应的大小,所以您可能会使用HTTP压缩,所以我怀疑这会造成很大的开销。第一个例子当然最好用123e4
来表达?@NPE你是对的——修改并包含了一些关于非常小/很大数量的潜在故障案例的信息。printf
与“%.4g”
足够接近吗?(在某些情况下太长了。)或者使用3位数字表示有效位,2位数字表示指数(偏置使指数00
表示-50
),嘿,普雷斯托,我发明了一种浮点数字表示法。说真的,如果你更关心简洁而不是精度,那么值得考虑这种表示法的一些变体。瞧,那些讨厌的e
s没有浪费空间。@mafso,我编辑了我的答案来比较“%.4g”
(以及.3f
和.4g
)使用我设计的场景。如果您知道您正在使用的数字的大致范围,您可以从这些示例输出中进行选择。谢谢。这看起来像。但是我实际上想要我在问题中给出的字符串形式。客户端是通过WebSocket接收JSON的浏览器。我不能要求客户端解压缩数字,尤其是因为不清楚哪些非结构化数据字段是数字,应该解包。如果我要走聪明的编码路线,我会使用类似于msgpack或protobuf或类似的东西。现在我只想知道,对于我使用标准C/C++描述(或接近它)的内容,是否有一个合理的API。
shift_count = 0;
while(value > 0xFFF) {
value = value >> 1;
shift_count++;
}