我正在使用一些就地代码来处理格式化用户存储的浮点数以供人类显示。
目前的实施方式是这样做的:
"{0:.24f}".format(some_floating_point).rstrip('0')
这很有意义,大部分都可以正常使用。但是当面对诸如0.0003
这样的价值时,事情就不会那样了。
>>> "{0:.24f}".format(0.0003).rstrip('0')
'0.000299999999999999973719'
进一步调查表明Python似乎根据请求的位数更改了基础表示?
>>> "{0:.15f}".format(0.0003)
'0.000300000000000'
>>> "{0:.20f}".format(0.0003)
'0.00029999999999999997'
我的假设是单精度与双精度。
用户输入这些值,将它们作为double存储在数据库中,并且稍后再次呈现表单时,将在字段中预先填充相同的值。因此,我需要这些表示的1:1映射。
因此,我的问题是:处理这种行为的优雅,更重要的安全方法是什么?到目前为止,我所做的最好的努力都涉及log10,并且不太理想,因为它很好。
编辑:正如Prune所指出的那样,该值实际上并没有改变,而是格式化的舍入将结转,导致一组9s变为0(d'oh)。这种行为是有道理的,但解决方案仍在逃避我。
答案 0 :(得分:1)
您正在接收存储的号码。 0.0003不能完全作为二进制分数存储。举例说明:
>>> 0.00029999999999999997 == 0.0003
True
打印格式以最低有效数字对数字进行舍入。双精度只会将问题推向更远的位置。要将问题完全“解决”到10眼,你需要切换到十进制算术,或者为足够接近更简单值的数字构建自己的字符串处理程序(小数部分中的可疑字符串为9或0) )。
这是一个功能的开始。我用0.0004测试它,它存储的头发超过0.0004; 9的情况留作练习:-)。
def str_round(x):
size = 6
nines = '9'*size
zeros = '0'*size
str = "{0:.24f}".format(x).rstrip('0')
str_len = len(str)
print str, str_len
if nines in str:
# replace leading digit with one more
pos = str.index(nines)
# ADD CODE HERE
# Turn the leading portion into an integer;
# increment and convert back to zero-leading string.
# Fill out the rest with zeros.
elif zeros in str:
# Change all trailing digits to 0
pos = str.index(zeros)
str = str[:pos] + '0'*(str_len - pos)
return str
print str_round(0.0004)