【问题标题】:Am I comparing (either a float or int value) against a decimal value correctly?我是否正确地将(浮点数或整数值)与十进制值进行比较?
【发布时间】:2019-08-08 20:10:41
【问题描述】:

我正在将价格表中的价格(乘以百分比)与数据库中存储的当前价格进行比较。

  • 数据库价格始终以十进制形式存储。
  • 价目表中的价格始终被读取为 float 或 int。

测试:

for recurringFee, plan_rate_id in data:
    for offer_name, pc_offer_id, agreement_type, purchase_unit, secondary_license_type, end_customer_type, pc_list_price,pc_erp_price in price_list:
        price_list_types.add(type(pc_erp_price).__name__)
        pba_db_types.add(type(recurringFee).__name__)
print(price_list_types)
print(pba_db_types)

输出:

{'float', 'int'}
{'Decimal'}

如果价格发生变化,我会将 db 值更新为新价格。

如果数据库中的当前价格为 0.45(例如),当我进行选择时,它总是被读取/存储为:

0.45000000

我相信 math.isclose() 函数可以帮助我。

当 math.isclose() 为 false 时,触发:

  1. 打印以筛选当前价格(不带尾随零)和新价格(四舍五入到小数点后 2 位)。
  2. 写入 csv 文件。
  3. 将新值(四舍五入到小数点后 2 位)附加到列表中,以便稍后通过 sql 更新查询进行更新。

现在的问题是它正在打印到屏幕并附加到列表中的实际更改和相同的值。

我正在使用 .format() 打印到屏幕

我尝试为 math.isclose 定义一个 rel_tol 值,但如果我不指定任何 rel_tol,我相信这些数字已经被正确比较

>>> fee = 6.51000000
>>> print(erp_price)
6.5068
>>> math.isclose(fee,erp_price)
False
>>> math.isclose(fee,erp_price,rel_tol=0.01)
True
>>> math.isclose(fee,erp_price,rel_tol=0.001)
True
>>> math.isclose(fee,erp_price,rel_tol=0.0001)
False
>>>

代码sn-p:

if not(math.isclose(pc_list_price,recurringFee)):
    print("Addons Markup: \n{}:\n{}\nPlan {}:\nYearly: {}\nOwner: {}\nPrice {} -> {}\n".format(res_name,offer_id,plan_id,yearly,owner_id,float(recurringFee),round(pc_list_price,2)))
    writer.writerow([owner_id,currency,plan_id,res_id,plan_rate_id,res_name,offer_id,float(recurringFee),round(pc_list_price,2),value,key])
    to_be_updated.append((owner_id,plan_id,plan_rate_id,round(pc_list_price,2),i))

输出:

Addons Markup: 
Dynamics 365 Customer Insights Addnl Profiles for Education:
77e8bce5-aa9e-47d3-ad59-5bd4bb13e5ac
Plan 244534:
Yearly: False
Owner: 1018324671
Price 478.15 -> 478.15

如果我只是打印原始值(删除打印中的任何圆形或浮点数),那么我会弄清楚它为什么打印看起来相同的值:

Addons Markup: 
Intune Extra Storage:
ced5f693-2d40-40ae-8848-9809ab1b0ee9
Plan 34285:
Yearly: False
Owner: 1018324671
Price 1.83000000 -> 1.8252000000000002

我的期望是:

Addons Markup: 
Intune Extra Storage:
ced5f693-2d40-40ae-8848-9809ab1b0ee9
Plan 34285:
Yearly: False
Owner: 1018324671
Price 1.83 -> 1.825
  1. 如何正确比较这些值?
  2. 如何记录到文件并打印到屏幕上人类可读的更改?

【问题讨论】:

  • 一个普遍的想法:floats are inaccurate。对于您的情况(如果我理解正确的话),我会指定一个“最小增量”(math.isclose() 中的abs_tol),以便在触发价格更新时清楚。如果将输出四舍五入为 2 位数字,例如为 0.01。

标签: python-3.x


【解决方案1】:

这里有两个不同的概念。 显示精度。如果您在进行计算(尤其是在浮点数上),您应该始终根据实际值进行计算,而不是“显示时的样子”。

使用浮点数(以及一般货币值)的最佳方法是使用decimal module

这是一个简单的例子:

import decimal

i = decimal.Decimal('1.83000000')
q = decimal.Decimal('1.8252000000000002')

z = i.quantize(decimal.Decimal('0.01'), rounding=decimal.ROUND_DOWN) # get a new rounded down value
v = q.quantize(decimal.Decimal('0.01'), rounding=decimal.ROUND_DOWN)

if z > v:
  print(f'{i:.3f} -> {q:.3f}') # use string formatting to control how its printed

输出是:

1.830 -> 1.825

这使得计算变得更简单,而无需处理 math.isclose(),您可以使用 decimal 进行“常规数学”,它会按预期工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-08-01
    • 1970-01-01
    • 2021-08-26
    • 1970-01-01
    • 2022-01-09
    • 1970-01-01
    • 2014-11-26
    • 1970-01-01
    相关资源
    最近更新 更多