【问题标题】:The decimal.Decimal() function is producing an unrounded resultdecimal.Decimal() 函数产生未舍入的结果
【发布时间】:2021-02-21 08:51:21
【问题描述】:

我是 Python 新手,我在 Python 的小数模块中的小数函数遇到问题。我知道,由于 Python 在内存中存储浮点值的方式,为了对它们执行计算以生成人类可读的结果,我们可以对结果使用 round 函数或使用 decimal.Decimal() 函数。

在下面的代码中,我创建了一个类 calc1,它只返回两个数字的加法和差值。然而,每当我运行它时,即使我的代码中包含了 decimal.Decimal(),结果仍然是不四舍五入的。

代码:

    import decimal as dec

    class calc1:
            'calc1 class is used for addition, subtraction only'
            obj_count = 0

            def __init__(self, value1, value2):
                    self.value1 = value1
                    self.value2 = value2
                    calc1.obj_count = calc1.obj_count + 1

            def add(self):
                    return dec.Decimal(self.value1 + self.value2)

            def sub(self):
                    return dec.Decimal(self.value1 - self.value2)

            def __str__(self):
                    return str(self.add()) + " " + str(self.sub())

    obj_list = []

    for i in range(5):
            obj_list.append(calc1(3 * i, 5.6 * i))
            print(obj_list[i])

输出:

0.0 0
8.6 -2.5999999999999996447286321199499070644378662109375 17.2 -5.199999999999999289457264239899814128875732421875 25.799999999999997 -7.7999999999999971578290569595992565155029296875 34.4 -10.39999999999999857891452847979962825775146484375

【问题讨论】:

  • 5.6 是到达decimal 模块之前的本机浮点值,5.6 * i 在不使用decimal 模块的情况下执行本机浮点运算。我不经常使用 Python,也不使用 decimal 模块,但我希望你会希望以 "5.6" 作为字符串开始,将其转换为 decimal 值,然后从那里继续算术,完全避免本机 Python 浮点数。

标签: python python-3.x floating-point decimal number-formatting


【解决方案1】:

您的问题是您将一个已经具有浮点精度的值传递给您的类,然后是 Decimal 类。

您可以通过将您希望分配给它的数字的字符串表示形式交给Decimal 来避免这种情况。

from decimal import Decimal

class Calc1:
    def __init__(self, val_1, val_2):
        # these are now Decimal objects
        self.val_1 = val_1
        self.val_2 = val_2
    
    def add(self):
        # the Decimal conversion can be removed here
        # since both numbers are already Decimals
        return self.val_1 + self.val_2

    def sub(self):
        return self.val_1 - self.val_2
   
    def __str__(self):
        return str(self.add()) + " " + str(self.sub())

lst = []
for i in range(5):
    i_as_dec = Decimal(i)
    # Here we multiply a decimal representation of each of our numbers
    # this will hand a Decimal object to the Calc1 class
    lst.append(Calc1(Decimal('3') * i_as_dec, Decimal('5.6') * i_as_dec))
    print(lst[i])

输出:

0.0 0.0
8.6 -2.6
17.2 -5.2
25.8 -7.8
34.4 -10.4

【讨论】:

  • 有没有办法将浮点变量转换为小数?我试图将转换为字符串的浮点数传递给 Decimal() ,它似乎仍然只工作了一半的时间。我刚刚在我的原始代码中编辑了 2 行:self.value1 = dec.Decimal(str(value1)) self.value2 = dec.Decimal(str(value2)) 并且它不起作用
  • 就像我在答案中提到的那样,如果您将任何值作为浮点数传递,它已经具有浮点精度。例如,您的解释器中的5.6 * 3 返回16.799999999999997。将该值交给str() 在转换为字符串之前不会以任何有意义的方式对其进行更改。您的选择是应用某种类型的舍入,或者从源处使用Decimals 开始,我的回答就是这样做。
【解决方案2】:

然而,无论何时我运行它,即使我在我的代码中包含了 decimal.Decimal(),结果仍然是不四舍五入的。

这符合decimal.Decimal 根据its docs 应该做的事情:

class decimal.Decimal(value="0", context=None) 构造一个新的 Decimal 基于价值的对象。 (...) 如果 value 是浮点数,则二进制 浮点值被无损转换为其精确的十进制 相等的。这种转换通常需要 53 位或更多位 精确。例如, Decimal(float('1.1')) 转换为 十进制('1.100000000000000088817841970012523233890533447265625')。

作为旁注decimal.Decimal 是类,而不是函数。

要生成人类可读的结果,我们可以对结果使用 round 函数或使用 decimal.Decimal() 函数。

除此之外,您可能会决定使用所谓的f-strings 来格式化您的输出,例如,如果我想在小数点后保留 4 位:

x = 0.1 + 0.1 + 0.1
print(x)  # 0.30000000000000004
print(f'{x:.4f}')  # 0.3000

请记住 f-string 仅在 python3.6 和更高版本中可用,如果您必须使用旧版本,请考虑使用其他格式化方法。

【讨论】:

  • 有没有办法将浮点值转换为十进制变量本身,而不是使用 f 字符串或其他格式化工具来仅仅更改打印输出?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-09-03
  • 2020-08-17
  • 1970-01-01
  • 1970-01-01
  • 2016-05-27
  • 1970-01-01
  • 2022-01-18
相关资源
最近更新 更多