Python如何将浮点数按其小数位数预设的最小步长递增

6

我已经搜索了几个小时,但无法找到简单的方法来完成以下操作。

Value 1 = 0.00531
Value 2 = 0.051959
Value 3 = 0.0067123

我希望将每个值都增加它的小数点位数(然而,数字必须保持与原始数字相同的小数点位数,并且每个值的小数位数不同,因此我感到困扰)。

Value 1 should be: 0.00532
Value 2 should be: 0.051960
Value 3 should be: 0.0067124

有没有简单的方法来实现上述功能,能够处理任意数量的小数?

谢谢。


7
浮点数在内部的表示不是十进制,而是二进制。因此,“0.1”例如是一个可表示的浮点数。它被近似为“0.099999 ...”或“0.1000 ...”,因此会非常不稳定。 - Willem Van Onsem
相关链接:https://dev59.com/G3RB5IYBdhLWcg3wj36c - Willem Van Onsem
1
如果你真的想要这个,那么你应该切换到非浮点表示(例如,一个整数加上一个给出小数位数的数字)。 - Tom Karzes
@TomKarzes的方法是可行的,但请注意,仅仅因为你看到的十进制表示是0.00532,实际上可能会有更多的小数位数,所以如果你没有看到整个表示,你可能会得到与预期不同的结果。 - alkasm
.1 + .2 == 0.30000000000000004。这里的“真正”的最后一位是什么? - ForceBru
3个回答

4

你看过标准模块 decimal 吗?

它可以规避浮点行为。

只是为了说明可以做什么。

import decimal
my_number = '0.00531'
mnd = decimal.Decimal(my_number)
print(mnd)
mnt = mnd.as_tuple()
print(mnt)
mnt_digit_new = mnt.digits[:-1] + (mnt.digits[-1]+1,)
dec_incr = decimal.DecimalTuple(mnt.sign, mnt_digit_new, mnt.exponent)
print(dec_incr)
incremented = decimal.Decimal(dec_incr)
print(incremented)

打印

0.00531
DecimalTuple(sign=0, digits=(5, 3, 1), exponent=-5)
DecimalTuple(sign=0, digits=(5, 3, 2), exponent=-5)
0.00532

或完整版(编辑后也带有任何数字,因此也适用于'0.199')...
from decimal import Decimal, getcontext

def add_one_at_last_digit(input_string):
    dec = Decimal(input_string)
    getcontext().prec = len(dec.as_tuple().digits)
    return dec.next_plus()

for i in ('0.00531', '0.051959', '0.0067123', '1', '0.05199'):
    print(add_one_at_last_digit(i))

打印

0.00532
0.051960
0.0067124
2
0.05200

2
正如其他评论者所指出的那样:您不应该使用浮点数,因为给定的数字0.1234会被转换为内部表示形式,您无法按照您想要的方式进一步处理它。这是故意模糊表述的。浮点数本身就是一个主题。这篇文章很好地解释了这个主题,并且是该主题的一个很好的入门材料。
话虽如此,您可以将输入作为字符串(例如,在从输入读取时不将其转换为浮点数)。然后您可以这样做:
from decimal import Decimal

def add_one(v):
    after_comma = Decimal(v).as_tuple()[-1]*-1
    add = Decimal(1) / Decimal(10**after_comma)
    return Decimal(v) + add

if __name__ == '__main__':
    print(add_one("0.00531"))
    print(add_one("0.051959"))
    print(add_one("0.0067123"))
    print(add_one("1"))

这段代码会打印出文字。
0.00532
0.051960
0.0067124
2

更新:

如果您需要处理浮点数,您可以尝试使用模糊逻辑来得到近似结果。 decimal 提供了一个 normalize 函数,可以降低小数表示的精度,使其与原始数字相匹配:

from decimal import Decimal, Context

def add_one_float(v):
    v_normalized = Decimal(v).normalize(Context(prec=16))
    after_comma = v_normalized.as_tuple()[-1]*-1
    add = Decimal(1) / Decimal(10**after_comma)
    return Decimal(v_normalized) + add

但请注意,16 的精度纯属实验性质,您需要尝试使用它来查看是否产生所需结果。如果您需要正确的结果,您不能选择这条路。


@dAJVqgVFsB 谢谢。你能给我的答案点个赞和/或接受吗?(这是在stackoverflow上的货币..) - hansaplast

0

使用数字作为输入,同时实现减法的一点改进:

import decimal 

def add_or_sub_one_at_last_digit(input_number,to_add = True):
    dec = decimal.Decimal(str(input_number))
    decimal.getcontext().prec = len(dec.as_tuple().digits)
    ret = dec.next_plus() if to_add else dec.next_minus()
    return ret 

a = 0.225487
# add
print(add_or_sub_one_at_last_digit(a))
# substract
print(add_or_sub_one_at_last_digit(a,False))

输出:

0.225488
0.225486

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接