【问题标题】:Adding 2 decimal numbers in strings, retaining precision在字符串中添加 2 个十进制数字,保持精度
【发布时间】:2019-08-09 09:16:59
【问题描述】:

我有 2 个字符串,每个字符串都包含一个十进制数,我们可以假设它们具有相同的精度。

我不能只硬编码精度,因为这些字符串集有时可能具有不同的精度。

我只是想将它们的两个值相加,并让总和保持上述值的精度。

其中一个值可能有负数,这就是为什么我想避免字符串拼接,这是我最初的想法。

我的代码:

str1 = "0.16107000" 
str2 = "0.00000270"
total = abs(float(str1)) + abs(float(str2))
print("Total is " + str(total))

输出:

Total is 0.16107269999999999

期望的输出:

Total is 0.16107270

另一个让事情变得更棘手的例子:

str1 = "70.00000000" 
str2 = "0.00131251"

我需要总数为70.00131251

最好的方法是什么?

【问题讨论】:

  • 这是个骗人的问题
  • “精度”是指小数位吗? (还有其他测量精度的方法,例如有效数字。)可能出现的最大小数位数和有效数字是多少?您使用的是哪个版本的 Python?
  • 正确,小数位。我正在使用 Python 3.7。小数点后的最大位数为 8。

标签: python python-3.x math rounding


【解决方案1】:
from decimal import *
getcontext().prec = 8
str1 = "0.16107000" 
str2 = "0.00000270"
total = Decimal(str1)+Decimal(str2)
print("Total is " + str(total))
# Total is 0.16107270

【讨论】:

  • 提问者说你不能“仅仅硬编码精度,因为这些字符串集有时可能具有不同的精度。”这个答案将精度硬编码到小数点后 8 位。
  • 类似于 ComplicatedPhenomenon 和 Rory Daulton 的解决方案,当 str1 = "70.00000000" 和 str2 = "0.00131251" 时,总数是 70.001313 而不是 70.00131251,这是我需要的。
  • @Dingo 然后你可以设置getcontext().prec = 10
【解决方案2】:

这是一些代码。它似乎比要求的要复杂,但是处理一般情况需要复杂性。如果这两个数字的小数位数不同,则此代码将使用较大的,如果字符串表示精确值,这就是您想要的。

def get_decimal_places(dec_str: str) -> int:
    """Return the number of decimal places expressed in a number in a
    string. The string must have only an optional leading sign, decimal
    digits, and an optional single decimal point. No check is done on
    these requirements. If the string has no decimal point, the returned
    value is zero.
    """
    if "." in dec_str:
        return len(dec_str) - dec_str.find(".") - 1
    else:
        return 0


str1 = "0.16107000" 
str2 = "0.00000270"

dec_places = max(get_decimal_places(str1), get_decimal_places(str2))
print(f"Total is {float(str1) + float(str2):.{dec_places}f}")

这段代码给出了想要的输出:

Total is 0.16107270

如果您使用其他示例,

str1 = "70.00000000"
str2 = "0.00131251"

这也给出了所需的输出:

Total is 70.00131251

对于你在回答中的例子,

str1 = "-70.00000000"
str2 = "0.00131251"

输出再次符合要求:

Total is -69.99868749

最后,对于这个棘手的例子

str1 = "0.10"
str2 = "0.0000"

输出也如愿:

Total is 0.1000

【讨论】:

  • 感谢您的回复。但是,这在以下情况下不起作用: str1 = "70.00000000" str2 = "0.00131251" 我需要总数为 70.00131251,但我最终得到 70.001313
  • @Dingo:感谢您在我的回答中指出错误。我现在改变了我的答案。我当前的代码适用于这种情况以及许多其他情况。
【解决方案3】:
>>> x = 3.1234567
>>> x = float('{:.3f}'.format(x))
>>> x
3.123

添加你的代码

x = float('{:.9f}'.format(total))
print(x)

【讨论】:

  • 我不认为这是一个严肃的问题。但是,.format() 会减少剩余的数字。他应该使用str(round(total, num_of_digits)) 舍入到最后一位。但又似乎是一个愚蠢的问题。
  • 我正在进行 API 调用并将这些数字作为字符串接收。我必须添加它们并进行另一个 API 调用,其中一个参数是总和,并且只接受我之前收到的相同精度。将我的问题视为“愚蠢”是非常粗鲁的。
【解决方案4】:

这是使用ComplicatedPhenomenon的原始代码,他的建议是根据小数点前的数字(不包括-符号)增加getcontext().prec,以及Rory Daulton的代码来确定getcontext()是什么。 prec 根据传递的字符串使用。

from decimal import Decimal, getcontext

def add_string_numbers(str1, str2):
    def get_decimal_places(dec_str: str) -> int:
        """Return the number of decimal places expressed in a number in a
        string. The string must have only an optional leading sign, decimal
        digits, and an optional single decimal point. If the string has no
        decimal point, the returned value is zero.
        """
        if "." in dec_str:
            return len(dec_str) - dec_str.find(".") + len([x for x in dec_str.split(".")[0] if x.isdigit()])
        else:
            return 0
    getcontext().prec = max(get_decimal_places(str1), get_decimal_places(str2))
    total = Decimal(str1) + Decimal(str2)    
    return total

str1 = "-70.00000000"
str2 = "0.00131251"

total = add_string_numbers(str1, str2)
print("Total is " + str(total))

结果:

Total is -69.99868749

【讨论】:

  • 请注意,我更改了答案,不再使用decimal 模块。我之前的代码并非在所有情况下都有效,而我相信我现在的代码可以。
猜你喜欢
  • 2012-06-18
  • 1970-01-01
  • 2020-12-23
  • 2020-02-05
  • 1970-01-01
  • 2023-04-01
  • 2012-09-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多