【问题标题】:What is the Smallest Nonzero Number that I can Reliably Generate?我可以可靠生成的最小非零数是多少?
【发布时间】:2021-01-20 05:46:12
【问题描述】:

我正在做一些图形类型的工作,我经常想将两点之间的斜率作为 dy / dx。但是,如果我的 dx 正好为零,我会得到一个被零除的错误。

如果 dx 为零,我可以将其设置为较小的值,例如 0.001。不过,我想提高我的解决方案的准确性。

对于这个给定的问题可能有更好的解决方案,但我确信存在其他问题,其可能的解决方案要求同样的事情:最小可能的非零数。

另外,获得它有多贵?这个数字是否有很大的可能性无法可靠地复制,可能是由于舍入误差?

【问题讨论】:

  • 我认为这是meta.stackexchange.com/questions/66377/what-is-the-xy-problem 我怀疑您是否可以使用最小的非零数字来实现您的目的。您真正想要的是仍然可以计算出有意义的斜率的最小数字。但是对于零的 delta x,如果它存在,则存在一个有意义的斜率,即“垂直”。所以我认为你真正应该做的是对任何 0-deltax 使用语义上的“垂直”,而不是将 deltax 更改为只给你一个看似有意义的斜率的东西。
  • 如何做到这一点当然是一个不同的问题。请更详细地描述您的背景。然后我们可以为您的需要寻找解决方案,而不是帮助您强制您目前遵循的最终可能是死路一条。
  • 为什么这个标签both C 和 Python?它们的浮点类型不等价。您正在寻找哪种语言的特定类型?你知道 Python 也有任意精度的有理类型吗?
  • 宫城先生,不,我不知道!我想知道每种语言的答案。 Yunnosch,我不是在寻找特定问题的解决方案。我问这样我可能能够更好地解决未来的问题。没有死胡同。

标签: python c divide-by-zero


【解决方案1】:

您可以为此使用decimal 模块吗?您可以使用以下方法制作一个非常小的固定浮点值:

import decimal
from decimal import Decimal

>>> almost_zero = Decimal((0, (1,), decimal.getcontext().Emin))
>>> almost_zero
Decimal('1E-999999')

这是一个非常小的数字,应该适合您的目的。

>>> 1 / almost_zero
Decimal('1E+999999')

或者你可以从sys.float_info中挖掘一些东西。

>>> import sys
>>> sys.float_info
sys.float_info(max=1.7976931348623157e+308, max_exp=1024, max_10_exp=308, min=2.2250738585072014e-308, min_exp=-1021, min_10_exp=-307, dig=15, mant_dig=53, epsilon=2.220446049250313e-16, radix=2, rounds=1)
>>> almost_zero = sys.float_info.min
>>> 1 / almost_zero
4.49423283715579e+307

【讨论】:

    【解决方案2】:

    我正在做一些图形类的东西

    那就考虑研究一下GNUplot的源代码(求灵感)。是free software.... 也可以看看GraphViz的源码里面。是open source

    我可以可靠生成的最小非零数是多少?

    理论上,这可能是特定于编译器的,也可能是特定于实现的。

    n1570 草案 C 标准在 §5.2.4.2.2 中提到了一些 DBL_EPSILON 宏....

    我建议显式编码 if (dy==0.0) return;,因为在当前的计算机上速度非常快。实际上,像if (fabs(dy)<4.0*DBL_EPSILON) return; 这样的测试可能会更好(但会运行得更慢)。

    关于 C 代码中的 rounding errors(在实践中),请参阅 floating point guide,然后考虑使用 Fluctuat toolCADNA toolABSINT tool

    如果您想分析二进制可执行文件中的舍入错误,请联系我在 BinSec 工作的同事。

    您还可以使用一些 arbitrary-precision arithmetic 库,例如 GMPlib

    这个数字是否有很大的可能性无法可靠地复制,可能是由于舍入误差?

    浮点舍入错误的概率static analysis(在编译时)高于最先进的水平。考虑撰写关于该主题的博士论文。您的博士生导师可能是美国的Patrick Cousot 或法国的Eric GoubaultSylvie PutotEmmanuel Haucourt。或者来自Frama-C 团队(法国巴黎附近)的一些同事(例如Franck Védrine)。还可以查看ACM SIGPLAN 会议的会议记录。

    也许在 2021 年中期,您可能会使用 RefPerSysBismon 来分析您的 C 代码(或者可能是您的 Python 代码;另请参阅 this)?在这种情况下,请通过电子邮件与我联系。

    请注意,浮点舍入错误确实杀死了数十人(并且可能解释了一些 Boeing 737 MAX 崩溃)。定点溢出与Ariane 501 failure 有关。所以你未来的博士(关于浮点错误的静态分析)可以由BoeingAirbusNASAESADassaultCNES 共同资助,可能还有国防(炮兵正在使用自 1940 年代以来的计算机)、机器人技术(想想神经外科中的 cobots)或汽车行业(因为 autonomous vehicles 使用浮点数)。

    另请阅读已故雅克·皮特拉 (Jacques Pitrat) 的 the blog。它与您的兴趣相关。

    2021 年,一个与浮点相关的有趣应用是模拟Covid-19 大流行。所以我想大医院也可以共同资助你的博士学位(例如,为了更好地估计social distancing...在欧洲,不同国家的推荐距离是不同的)。

    当然,在美国,NSF(也许还有 Google 或 Facebook)也可以共同资助您的博士学位 (我猜美国DoD 也可以共同资助它,因为过去导弹或武器的四舍五入误差确实杀死了几名美国士兵。

    附言。如果你开始攻读这些主题的博士学位,请给我发电子邮件。我有兴趣。

    【讨论】:

      【解决方案3】:

      下面是一个程序,可以帮助您实现所需的值。这些值都是在文件<float.h> 中定义的常量,描述了floatdouble 使用的位数等常量,以及您可以在程序中使用的最大值和最小值。

      DBL_MINDBL_TRUE_MINDBL_EPSILON 值得解释一下。您应该阅读有关浮点二进制数的标准 IEEE 754。第一个是可以以全精度表示的最小值,在此之下您可以继续表示数字,但它们会失去越来越多的精度,直到您在 DBL_TRUE_MIN 中只生成一个位,这是您机器中可表示的最小值.但在我看来,您正在寻找的是DBL_EPSILON,这是浮点中两个连续数字之间存在的差距。由于浮点数是相对大小,它以1.01.0 之后的下一个数字之间的差异给出,这意味着数字不能比这更接近(您需要将此*_EPSILON 乘以提供比例尺,以了解在该比例尺下一个数字与下一个数字之间的距离。

      为您提供值的程序如下:

      #include <stdio.h>
      #include <float.h>
      
      #define P(_nam,_fmt) printf("%20s = "_fmt"\n", #_nam, _nam)
      
      int main()
      {
              P(FLT_DIG,     "%18d");
              P(FLT_MAX,     "%18.6g");
              P(FLT_EPSILON, "%18.6g");
              P(FLT_MIN,     "%18.6g");
      #if FLT_HAS_SUBNORM
              P(FLT_TRUE_MIN,"%18.2g");
      #endif
              puts("");
              P(DBL_DIG,     "%18d");
              P(DBL_MAX,     "%18.15lg");
              P(DBL_EPSILON, "%18.15lg");
              P(DBL_MIN,     "%18.15lg");
      #if DBL_HAS_SUBNORM
              P(DBL_TRUE_MIN,"%18.2lg");
      #endif
      }
      

      它在我的系统上给出的结果是(显示floatdouble 值):

                   FLT_DIG =                  6
                   FLT_MAX =        3.40282e+38
               FLT_EPSILON =        1.19209e-07
                   FLT_MIN =        1.17549e-38
              FLT_TRUE_MIN =            1.4e-45
      
                   DBL_DIG =                 15
                   DBL_MAX = 1.79769313486232e+308
               DBL_EPSILON = 2.22044604925031e-16
                   DBL_MIN = 2.2250738585072e-308
              DBL_TRUE_MIN =           4.9e-324
      

      【讨论】:

        猜你喜欢
        • 2015-04-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-11-12
        • 2010-11-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多