如何避免浮点错误?

tem*_*ame 19 python floating-point python-3.x floating-point-precision

我试图编写一个近似平方根的函数(我知道有数学模块......我想自己做),我被浮点运算搞砸了.你怎么能避免这种情况?

def sqrt(num):
    root = 0.0
    while root * root < num:
        root += 0.01
    return root
Run Code Online (Sandbox Code Playgroud)

使用它有以下结果:

>>> sqrt(4)
2.0000000000000013
>>> sqrt(9)
3.00999999999998
Run Code Online (Sandbox Code Playgroud)

我意识到我可以使用round(),但我希望能够让它真正准确.我希望能够计算出6或7位数.如果我四舍五入,这是不可能的.我想了解如何在Python中正确处理浮点计算.

Tim*_*ers 27

这与Python无关 - 您可以使用硬件的二进制浮点运算在任何语言中看到相同的行为.首先阅读文档.

阅读完之后,您将更好地理解您没有在代码中添加百分之一.这正是您要添加的内容:

>>> from decimal import Decimal
>>> Decimal(.01)
Decimal('0.01000000000000000020816681711721685132943093776702880859375')
Run Code Online (Sandbox Code Playgroud)

该字符串显示二进制浮点的精确十进制值(C中的"双精度")近似于精确的十进制值0.01.你真正添加的东西比1/100大一点.

控制浮点数字错误是称为"数值分析"的字段,并且是一个非常大且复杂的主题.只要您对浮点数只是十进制值的近似值感到震惊,请使用该decimal模块.这将为你带走一个"浅薄"问题的世界.例如,鉴于您对函数的这一小修改:

from decimal import Decimal as D

def sqrt(num):
    root = D(0)
    while root * root < num:
        root += D("0.01")
    return root
Run Code Online (Sandbox Code Playgroud)

然后:

>>> sqrt(4)
Decimal('2.00')
>>> sqrt(9)
Decimal('3.00')
Run Code Online (Sandbox Code Playgroud)

它并不是更准确,但在简单的例子中可能不那么令人惊讶,因为现在它只增加百分之一.

另一种方法是坚持浮动,并添加东西,作为二进制浮点精确表示:形式的值I/2**J.例如,不添加0.01,而是添加0.125(1/8)或0.0625(1/16).

然后查找"牛顿方法"计算平方根;-)

  • @Srinesh - 尝试`十进制('4') - 十进制('3.2'). (5认同)

the*_*heX 5

我的意思是,有诸如decimal和之类的模块fractions。但我专门为这些问题开设了一个课程。此类仅解决加法、减法、乘法、取整除法、除法和模数。但很容易扩展。它基本上将浮点数转换为列表([浮点数,乘以浮点数得到整数的十次方])并从那里进行算术运算。Python 中的整数比浮点数更准确。这就是这个类所利用的。所以,事不宜迟,代码如下:

\n\n
class decimal():\n    # TODO: # OPTIMISE: code to maximize performance\n    """\n    Class decimal, a more reliable alternative to float. | v0.1\n    ============================================================\n            Python\'s floats (and in many other languages as well) are\n    pretty inaccurate. While on the outside it may look like this:\n\n    .1 + .1 + .1\n\n            But on the inside, it gets converted to base 2. It tells\n    the computer, "2 to the power of what is 0.1?". The\n    computer says, "Oh, I don\'t know; would an approximation\n    be sufficient?"\n    Python be like, "Oh, sure, why not? It\'s not like we need to\n    give it that much accuracy."\n            And so that happens. But what they ARE good at is\n    everything else, including multiplying a float and a\n    10 together. So I abused that and made this: the decimal\n    class. Us humans knows that 1 + 1 + 1 = 3. Well, most of us\n    anyway but that\'s not important. The thing is, computers can\n    too! This new replacement does the following:\n\n            1. Find how many 10 ^ n it takes to get the number inputted\n                    into a valid integer.\n            2. Make a list with the original float and n (multiplying the by\n                    10^-n is inaccurate)\n\n            And that\'s pretty much it, if you don\'t count the\n    adding, subtracting, etc algorithm. This is more accurate than just\n    ".1 + .1 + .1". But then, it\'s more simple than hand-typing\n    (.1 * 100 + .01 * 100 + .1 * 100)/100\n    (which is basically the algorithm for this). But it does have it\'s costs.\n    --------------------------------------------------------------------------\n\n    BAD #1: It\'s slightly slower then the conventional .1 + .1 + .1 but\n        it DOES make up for accuracy\n\n    BAD #2: It\'s useless, there are many libraries out there that solves the\n            same problem as this. They may be more or less efficient than this\n            method. Thus rendering this useless.\n    --------------------------------------------------------------------------\n    And that\'s pretty much it! Thanks for stopping by to read this doc-string.\n    --------------------------------------------------------------------------\n        Copyright \xc2\xa9 2020 Bryan Hu\n\n        Permission is hereby granted, free of charge, to any person obtaining\n        a copy of this software and associated documentation files\n        (the "Software"), to deal in the Software without restriction,\n        including without limitation the rights to use, copy, modify,\n        merge, publish, distribute, sub-license, and/or sell copies of\n        the Software, and to permit persons to whom the Software is\n        furnished to do so, subject to the following conditions:\n\n        The above copyright notice and this permission notice shall be included\n        in all copies or substantial portions of the Software.\n\n        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n        OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n        MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n        IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n        CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n        TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n        SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n    """\n\n    def __init__(self, number):\n        super(decimal, self).__init__()\n        if number is iter:\n            processed = float(number[0])\n        else:\n            processed = float(number)\n        x = 10\n        while round(processed * x) != processed * x:\n            x *= 10\n        self.number = [processed, x]\n\n    def __add__(self, other):\n        the_other_number, num = list(other), list(self.number)\n        try:\n            maximum = max(\n                float(num[1]), float(the_other_number[1]))\n            return decimal(\n                (num[0] * maximum + the_other_number[0] * maximum) / maximum)\n        except IndexError:\n            raise "Entered {}, which has the type {},\\\n             is not a valid type".format(\n                other, type(other))\n\n    def __float__(self):\n        return float(self.number[0])\n\n    def __bool__(self):\n        return bool(self.number[0])\n\n    def __str__(self):\n        return str(self.number)\n\n    def __iter__(self):\n        return (x for x in self.number)\n\n    def __repr__(self):\n        return str(self.number[0])\n\n    def __sub__(self, other):\n        the_other_number, num = list(other), list(self.number)\n        try:\n            maximum = max(\n                float(num[1]), float(the_other_number[1]))\n            return decimal(\n                (num[0] * maximum - the_other_number[0] * maximum) / maximum)\n        except IndexError:\n            raise "Entered {}, which has the type {},\\\n         is not a valid type".format(\n                other, type(other))\n\n    def __div__(self, other):\n        the_other_number, num = list(other), list(self.number)\n        try:\n            maximum = max(\n                float(num[1]), float(the_other_number[1]))\n            return decimal(\n                ((num[0] * maximum) / (\n                    the_other_number[0] * maximum)) / maximum)\n        except IndexError:\n            raise "Entered {}, which has the type {},\\\n         is not a valid type".format(\n                other, type(other))\n\n    def __floordiv__(self, other):\n        the_other_number, num = list(other), list(self.number)\n        try:\n            maximum = max(\n                float(num[1]), float(the_other_number[1]))\n            return decimal(\n                ((num[0] * maximum) // (\n                    the_other_number[0] * maximum)) / maximum)\n        except IndexError:\n            raise "Entered {}, which has the type {},\\\n         is not a valid type".format(\n                other, type(other))\n\n    def __mul__(self, other):\n        the_other_number, num = list(other), list(self.number)\n        try:\n            maximum = max(\n                float(num[1]), float(the_other_number[1]))\n            return decimal(\n                ((num[0] * maximum) * (\n                    the_other_number[0] * maximum)) / maximum)\n        except IndexError:\n            raise "Entered {}, which has the type {},\\\n         is not a valid type".format(\n                other, type(other))\n\n    def __mod__(self, other):\n        the_other_number, num = list(other), list(self.number)\n        try:\n            maximum = max(\n                float(num[1]), float(the_other_number[1]))\n            return decimal(\n                ((num[0] * maximum) % (\n                    the_other_number[0] * maximum)) / maximum)\n        except IndexError:\n            raise "Entered {}, which has the type {},\\\n         is not a valid type".format(\n                other, type(other))\n    # Pastebin: https://pastebin.com/MwzZ1W9e\n
Run Code Online (Sandbox Code Playgroud)\n

  • 嘿,我很感谢你为此付出的努力!我希望它对你有用。但我永远不会推荐使用自行开发且大部分未经测试的代码来替代处理编程计算敏感方面的标准化模块和库。 (8认同)
  • 我知道,但我确实希望这在将来会有用。 (2认同)