Movatterモバイル変換


[0]ホーム

URL:


Skip to content
Search Gists
Sign in Sign up

Instantly share code, notes, and snippets.

@PythonCHB
Last activeAugust 29, 2015 14:13
    • Star(0)You must be signed in to star a gist
    • Fork(0)You must be signed in to fork a gist

    Select an option

    Save PythonCHB/6e9ef7732a9074d9337a to your computer and use it in GitHub Desktop.
    Sample implementation of an "closeness" checker for floating point for Python
    #!/usr/bin/env python3
    """
    A proposed implementation for an "is_close" implementation for floating point
    (and complex) numbers for python.
    This is an attempt to implement the approach used by Boost:
    http://www.boost.org/doc/libs/1_34_0/libs/test/doc/components/test_tools/floating_point_comparison.html
    With adjustments inspired by discussion on python-ideas list the code written
    by Steven D'Aprano for the statistics module tests.
    """
    defis_close(u,v,tol=1e-12,min_tol=0.0):
    """
    Determines if two values are close to each other. Two values are close if
    the absolute value of their difference is less than tol times both of the
    values. i.e. tol is a relative difference. The result is symmetric, i.e.:
    is_close(u,v) == is_close(v,u)
    Note that if one of the values is zero, then nothing is "relatively close"
    to it (except zero itself). If you want a tolerance for near-zero
    values, then you can set min_tol to a value greater than zero. But be
    cautious if u an v may be very small, the min_tol could overwhelm any
    relative tolerance computed.
    :param u: one of the values
    :param v: the other value
    :param tol=1e-12: the relative tolerance
    NOTE: an arbitrary value for now -- how to choose good default?
    :param min_tol=None: The maximum absolute tolerance near zero. If one
    of the
    arguments is zero, then no value greater than
    zero will ever be "close" to zero on a relative
    scale.
    NOTE: -inf, inf and NaN behave as they "should"
    """
    iftol<0ormin_tol<0:
    raiseValueError('error tolerances must be non-negative')
    ifu==v:# short-circuit exact equality
    returnTrue
    diff=abs(u-v)
    ## NOTE: using and, rather than if checks or max() allows it to run a bit
    ## faster, and lets NaN and inf do the right thing automagically.
    result= ((diff<=tol*abs(u))and
    (diff<=tol*abs(v))or
    (diff<=min_tol)
    )
    returnresult
    if__name__=="__main__":
    ## some simple tests
    # same values had better work!
    exact_values_examples= [(2.0,2.0),
    (0.1e200,0.1e200),
    ]
    foru,vinexact_values_examples:
    ifnotis_close(u,v,tol=1e-12):
    print("FAIL: {},{} should be close".format(u,v))
    # negative and positive zero
    assertis_close(0.0,-0.0)
    # very close values:
    close_enough_examples= [(1.000000000001,1.000000000002),
    (1e12+1.0,1e12+2.0),
    (1e13-1.0,1e13-2.0),
    (-1e12-1.0,-1e12-2.0),
    ]
    tol=1e-12
    foru,vinclose_enough_examples:
    ifnotis_close(u,v,tol=tol):
    print("FAIL: {},{} should be close to tol: {}".format(u,v,tol))
    tol=1e-14
    foru,vinclose_enough_examples:
    ifis_close(u,v,tol=tol):
    print("FAIL: {},{} should be not be close to tol: {}"
    .format(u,v,tol))
    # ## potential overflow:
    # ## note the boost docs talk about this, but I can't get it to overflow
    # ## and cause a problem. Maybe they were concerned about really large
    # ## values of tol???
    overflow_examples= [(1e308+1e294,1e308+2e294),
    ]
    tol=1e-12
    foru,vinoverflow_examples:
    ifnotis_close(u,v,tol=tol):
    print("FAIL: {},{} should be close to tol: {}".format(u,v,tol))
    # ## checking close to zero
    zero_examples= [(0.0,1e-15),
    (1e-15,0.0),
    ]
    tol=1e-13
    min_tol=0.0# nothing should be close
    foru,vinzero_examples:
    ifis_close(u,v,tol=tol,min_tol=min_tol):
    print("FAIL: {},{} should be NOT close to tol: {}".format(u,v,tol))
    tol=1e-13
    min_tol=1e-12# very small should hold.
    foru,vinzero_examples:
    ifnotis_close(u,v,tol=tol,min_tol=min_tol):
    print("FAIL: {},{} should be close to within min_tol: {}".format(u,v,min_tol))
    ## NaN, etc tests
    nan=float('nan')
    inf=float('inf')
    neginf=-inf
    non_real_examples= [(nan,1.0),
    (1.0,nan),
    (nan,nan),
    (inf,1.0),
    (1e300,inf),
    (-inf,-1e300),
    (-1e305,-inf)
    ]
    tol=1e-13
    min_tol=1e-12# very small should hold.
    foru,vinnon_real_examples:
    ifis_close(u,v,tol=tol,min_tol=min_tol):
    print("FAIL: {},{} should NOT be close to within min_tol: {}".format(u,v,min_tol))
    non_real_equal= [(inf,inf),
    (-inf,inf),
    ]
    tol=1e-13
    min_tol=1e-12# very small should hold.
    foru,vinnon_real_equal:
    ifnotis_close(u,v,tol=tol,min_tol=min_tol):
    print("FAIL: {},{} should be close to within min_tol: {}".format(u,v,min_tol))
    # ## complex tests
    # ## complex numbers will be handled by:
    # ## is_close(x.real, y.real) and is_close(x.imag, y.imag)
    # ## (but i haven't written any code for that yet)
    # # complex_examples = [(1.0+1.0j, 1.000000000001+1.0j ),
    # # (1.0+1.0j, 1.0+1.000000000001j ),
    # # (-1.0+1.0j, -1.000000000001+1.0j ),
    # # (1.0-1.0j, 1.0-0.999999999999j ),
    # # ]
    # # tol = 1e-12
    # # for u, v in complex_examples:
    # # if not is_close(u, v, tol=tol):
    # # print("FAIL: {},{} should be close to tol: {}".format(u, v, tol))
    # # tol = 1e-13
    # # for u, v in complex_examples:
    # # if is_close(u, v, tol=tol):
    # # print("FAIL: {},{} should be NOT close to tol: {}".format(u, v, tol))
    Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment

    [8]ページ先頭

    ©2009-2026 Movatter.jp