我的用例是将数字写入JSON文档,其中大小最小化比非常小/大数字的精度更重要。这些数字通常代表常见的单位,如毫秒或米,往往会落入[0.001,1000]范围。
基本上我想设置一个最大字符长度。例如,如果限制为五个字符,则:
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
此测试用例似乎在长度约束内传达了大部分信息。
它确实失败,数字被提升到[-99,999]范围之外的权力,并且该范围将根据强加的限制而变化。也许这里的失败案例只是在这些极少数情况下写一个更长的字符串。
这是理想的,但如果另一个解决方案相对接近,可能会截断而不是舍入,而不是利用科学/取幂符号,我可以自己实现它。
编辑这里printf
%.3f
%.3g
,%.4g
,printf("%.3f");
match 0 - 1.23457e+06 -> 1234567.000 expected 12e5
match 0 - 12345.6 -> 12345.600 expected 12346
match 0 - 1234.56 -> 1234.560 expected 1235
match 0 - 123.456 -> 123.456 expected 123.5
match 0 - 12.3456 -> 12.346 expected 12.35
match 1 - 1.23456 -> 1.235
match 0 - 1.2345 -> 1.234 expected 1.235
match 1 - 1.234 -> 1.234
match 0 - 1.23 -> 1.230 expected 1.23
match 0 - 1.2 -> 1.200 expected 1.2
match 0 - 1 -> 1.000 expected 1
match 1 - 0.11111 -> 0.111
match 1 - 0.01111 -> 0.011
match 1 - 0.00111 -> 0.001
match 0 - 0.00011 -> 0.000 expected 11e-4
match 0 - 1e-05 -> 0.000 expected 1e-5
match 1 - 0.11111 -> 0.111
match 1 - 0.01111 -> 0.011
match 1 - 0.00111 -> 0.001
match 0 - 0.00011 -> 0.000 expected 11e-4
match 0 - 1e-05 -> 0.000 expected 1e-5
printf("%.3g");
match 0 - 1.23457e+06 -> 1.23e+06 expected 12e5
match 0 - 12345.6 -> 1.23e+04 expected 12346
match 0 - 1234.56 -> 1.23e+03 expected 1235
match 0 - 123.456 -> 123 expected 123.5
match 0 - 12.3456 -> 12.3 expected 12.35
match 0 - 1.23456 -> 1.23 expected 1.235
match 0 - 1.2345 -> 1.23 expected 1.235
match 0 - 1.234 -> 1.23 expected 1.234
match 1 - 1.23 -> 1.23
match 1 - 1.2 -> 1.2
match 1 - 1 -> 1
match 1 - 0.11111 -> 0.111
match 0 - 0.01111 -> 0.0111 expected 0.011
match 0 - 0.00111 -> 0.00111 expected 0.001
match 0 - 0.00011 -> 0.00011 expected 11e-4
match 0 - 1e-05 -> 1e-05 expected 1e-5
match 1 - 0.11111 -> 0.111
match 0 - 0.01111 -> 0.0111 expected 0.011
match 0 - 0.00111 -> 0.00111 expected 0.001
match 0 - 0.00011 -> 0.00011 expected 11e-4
match 0 - 1e-05 -> 1e-05 expected 1e-5
printf("%.4g");
match 0 -> 1.23457e+06 -> 1.235e+06 expected 12e5
match 0 -> 12345.6 -> 1.235e+04 expected 12346
match 1 -> 1234.56 -> 1235
match 1 -> 123.456 -> 123.5
match 1 -> 12.3456 -> 12.35
match 1 -> 1.23456 -> 1.235
match 0 -> 1.2345 -> 1.234 expected 1.235
match 1 -> 1.234 -> 1.234
match 1 -> 1.23 -> 1.23
match 1 -> 1.2 -> 1.2
match 1 -> 1 -> 1
match 0 -> 0.11111 -> 0.1111 expected 0.111
match 0 -> 0.01111 -> 0.01111 expected 0.011
match 0 -> 0.00111 -> 0.00111 expected 0.001
match 0 -> 0.00011 -> 0.00011 expected 11e-4
match 0 -> 1e-05 -> 1e-05 expected 1e-5
match 0 -> 0.11111 -> 0.1111 expected 0.111
match 0 -> 0.01111 -> 0.01111 expected 0.011
match 0 -> 0.00111 -> 0.00111 expected 0.001
match 0 -> 0.00011 -> 0.00011 expected 11e-4
match 0 -> 1e-05 -> 1e-05 expected 1e-5
比较产生code here) :
{{1}}
答案 0 :(得分:1)
用于将特定范围内的数字打包成最小的无符号整数:
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 << 4) | shift_count
。
这样,您可以将数字压缩到4个十六进制数字。对于上面的示例,0.001将变为0x0000(精确表示0.001),123.456将变为0xF115(实际表示123.425),100000将变为0xBEBF(实际表示为99975.169)。
答案 1 :(得分:1)
您似乎必须编写自己的转换例程。 ecvt
库函数可能会有所帮助。
但我只是使用%.3g
或%.4g
格式,在指数之前删除多余的加号和前导零,并将其称为一天。这主要留下一些可以优化的小数点。既然你非常关心你的JSON响应的大小,你可能会使用HTTP压缩,所以我怀疑这会导致很多开销。