【问题标题】:python float addition results with unexpected decimal placespython浮点加法结果具有意外的小数位
【发布时间】:2020-05-24 11:12:26
【问题描述】:

我有以下代码通过计算订单来检测股票交易:

import json

orders = '[{"side": "SELL", "executedQty": "0.046"}, {"side": "SELL", "executedQty": "0.041"}, {"side": "SELL", "executedQty": "0.056"}, {"side": "SELL", "executedQty": "0.140"}, {"side": "BUY", "executedQty": "0.283"}]'
orders = json.loads(orders)

cur_qty = 0
raw_trades = []
trade = []
trade_side = None
for order in orders:
    if trade_side is None:
        trade_side = order['side']

    numbers_after_decimal = len(order['executedQty'].split('.')[-1])
    order_qty = float(order['executedQty'])
    order_qty = round(order_qty, numbers_after_decimal)

    if trade_side == order['side']:
        cur_qty += order_qty
    else:
        cur_qty -= order_qty

    trade.append(order)
    if cur_qty == 0:
        raw_trades.append(trade)
        trade_side = None
        trade = []

在这个例子中,订单只有 1 笔交易(我们卖出 0.046 + 0.041 + 0.056 + 0.140 = 0.283(入场),我们买入 0.283(离场))

问题是,当运行此代码时,由于某种原因,当在 for 循环中时,顺序是 {"side": "SELL", "executedQty": "0.140"}cur_qty = 0.143,当我添加它们时,结果是 0.28300000000000003

这弄乱了整个计数,因为我搜索 cur_qty == 0 以知道交易已经结束(我卖掉了我买的所有东西,反之亦然)。

试图将浮点数四舍五入到它的字符串小数位数,但它一直在发生。

任何想法如何解决这个问题,四舍五入没有帮助

【问题讨论】:

  • 请参阅:stackoverflow.com/questions/588004/… 在作为单独问题提问之前在网站上搜索答案是一种健康的做法。
  • @user79161,我确实在网上搜索过,但没有找到这个答案。然而,答案是谈论它为什么会发生,而不是说四舍五入(我已经尝试过),我没有看到其他解决方案,这就是这个问题的意义所在。我该如何克服这个问题并获得0.283 而不是0.28300000000000003
  • 你没有得到答案。 错误不能以一般方式克服。一般方式,我的意思是一种可以应用于以该形式表示的所有分数的方法。至少这是我在阅读我提到的答案和其中提供的链接后得出的结论。我相信你应该再读一遍。

标签: python floating-point decimal


【解决方案1】:

所以在阅读了@user79161 的答案后,我找到了以下解决方案——我还根据cur_qtyorder_qty 的字符串表示中的较高小数点对数字进行了四舍五入。

这就是代码现在的样子:

import json

orders = '[{"side": "SELL", "executedQty": "0.046"}, {"side": "SELL", "executedQty": "0.041"}, {"side": "SELL", "executedQty": "0.056"}, {"side": "SELL", "executedQty": "0.140"}, {"side": "BUY", "executedQty": "0.283"}]'
orders = json.loads(orders)

cur_qty = 0
raw_trades = []
trade = []
trade_side = None
for order in orders:
    if trade_side is None:
        trade_side = order['side']

    numbers_after_decimal = len(order['executedQty'].split('.')[-1])
    order_qty = float(order['executedQty'])
    order_qty = round(order_qty, numbers_after_decimal)

    numbers_after_decimal_cur_qty = len(str(cur_qty).split('.')[-1])

    decimal_numbers = max([numbers_after_decimal_cur_qty, numbers_after_decimal])

    if trade_side == order['side']:
        cur_qty += order_qty
    else:
        cur_qty -= order_qty

    cur_qty = round(cur_qty, decimal_numbers)

    trade.append(order)
    if cur_qty == 0:
        raw_trades.append(trade)
        trade_side = None
        trade = []

【讨论】:

  • 这是一个糟糕的解决方案。只需将所有股票数量转换为某个单位的整数倍,例如股票的千分之一,并使用整数运算。
  • @EricPostpischil 为什么这是一个糟糕的解决方案?你的建议怎么样?
  • 首先,您在离散单元中工作,因此您应该使用为此设计的解决方案。那就是整数算术。整数运算旨在进行精确的整数运算。浮点运算旨在逼近实数运算。只要您只是增加和减少数量,您就应该使用为此设计的解决方案。 (如果您开始深入研究数学,例如计算利率或投资回报率,那么浮点数可能更适合 - 但您需要了解更多有关浮点运算的知识才能正确使用它。)
  • 第二,四舍五入的计算成本很高。即使以错误的方式进行(乘以 10 的幂,舍入为整数,除以 10 的幂)也会在简单的加法和减法中添加不必要的操作。以正确的方式(产生最接近的可表示结果而不会从乘法中舍入误差)会更昂贵。 (不知道Python的round函数用的是哪个。)既然没必要(整数解就好),就是浪费计算资源。
  • 第三,对于数量和精度都受限的数字的简单加法和减法,舍入可能就足够了,但是,一般来说,通过将小的舍入误差放大到大的。最近,我确实在另一个 Stack Overlow 问题中提供了一个舍入解决方案,但我这样做时明确指定了所涉及数字的限制。这种对浮点的操作应该在清楚了解所涉及的问题的情况下完成。
猜你喜欢
  • 2022-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多