def approx(expected, rel=None, abs=None, nan_ok=False):
<EOL>__tracebackhide__ = True<EOL>if isinstance(expected, Decimal):<EOL><INDENT>cls = ApproxDecimal<EOL><DEDENT>elif isinstance(expected, Number):<EOL><INDENT>cls = ApproxScalar<EOL><DEDENT>elif isinstance(expected, Mapping):<EOL><INDENT>cls = ApproxMapping<EOL><DEDENT>elif _is_numpy_array(expected):<EOL><INDENT>cls = ApproxNumpy<EOL><DEDENT>elif (<EOL>isinstance(expected, Iterable)<EOL>and isinstance(expected, Sized)<EOL>and not isinstance(expected, STRING_TYPES)<EOL>):<EOL><INDENT>cls = ApproxSequencelike<EOL><DEDENT>else:<EOL><INDENT>raise _non_numeric_type_error(expected, at=None)<EOL><DEDENT>return cls(expected, rel, abs, nan_ok)<EOL>
Assert that two numbers (or two sets of numbers) are equal to each other
within some tolerance.

Due to the `intricacies of floating-point arithmetic`__, numbers that we
would intuitively expect to be equal are not always so::

    >>> 0.1 + 0.2 == 0.3
    False

__ https://docs.python.org/3/tutorial/floatingpoint.html

This problem is commonly encountered when writing tests, e.g. when making
sure that floating-point values are what you expect them to be.  One way to
deal with this problem is to assert that two floating-point numbers are
equal to within some appropriate tolerance::

    >>> abs((0.1 + 0.2) - 0.3) < 1e-6
    True

However, comparisons like this are tedious to write and difficult to
understand.  Furthermore, absolute comparisons like the one above are
usually discouraged because there's no tolerance that works well for all
situations.  ``1e-6`` is good for numbers around ``1``, but too small for
very big numbers and too big for very small ones.  It's better to express
the tolerance as a fraction of the expected value, but relative comparisons
like that are even more difficult to write correctly and concisely.

The ``approx`` class performs floating-point comparisons using a syntax
that's as intuitive as possible::

    >>> from pytest import approx
    >>> 0.1 + 0.2 == approx(0.3)
    True

The same syntax also works for sequences of numbers::

    >>> (0.1 + 0.2, 0.2 + 0.4) == approx((0.3, 0.6))
    True

Dictionary *values*::

    >>> {'a': 0.1 + 0.2, 'b': 0.2 + 0.4} == approx({'a': 0.3, 'b': 0.6})
    True

``numpy`` arrays::

    >>> import numpy as np                                                          # doctest: +SKIP
    >>> np.array([0.1, 0.2]) + np.array([0.2, 0.4]) == approx(np.array([0.3, 0.6])) # doctest: +SKIP
    True

And for a ``numpy`` array against a scalar::

    >>> import numpy as np                                         # doctest: +SKIP
    >>> np.array([0.1, 0.2]) + np.array([0.2, 0.1]) == approx(0.3) # doctest: +SKIP
    True

By default, ``approx`` considers numbers within a relative tolerance of
``1e-6`` (i.e. one part in a million) of its expected value to be equal.
This treatment would lead to surprising results if the expected value was
``0.0``, because nothing but ``0.0`` itself is relatively close to ``0.0``.
To handle this case less surprisingly, ``approx`` also considers numbers
within an absolute tolerance of ``1e-12`` of its expected value to be
equal.  Infinity and NaN are special cases.  Infinity is only considered
equal to itself, regardless of the relative tolerance.  NaN is not
considered equal to anything by default, but you can make it be equal to
itself by setting the ``nan_ok`` argument to True.  (This is meant to
facilitate comparing arrays that use NaN to mean "no data".)

Both the relative and absolute tolerances can be changed by passing
arguments to the ``approx`` constructor::

    >>> 1.0001 == approx(1)
    False
    >>> 1.0001 == approx(1, rel=1e-3)
    True
    >>> 1.0001 == approx(1, abs=1e-3)
    True

If you specify ``abs`` but not ``rel``, the comparison will not consider
the relative tolerance at all.  In other words, two numbers that are within
the default relative tolerance of ``1e-6`` will still be considered unequal
if they exceed the specified absolute tolerance.  If you specify both
``abs`` and ``rel``, the numbers will be considered equal if either
tolerance is met::

    >>> 1 + 1e-8 == approx(1)
    True
    >>> 1 + 1e-8 == approx(1, abs=1e-12)
    False
    >>> 1 + 1e-8 == approx(1, rel=1e-6, abs=1e-12)
    True

If you're thinking about using ``approx``, then you might want to know how
it compares to other good ways of comparing floating-point numbers.  All of
these algorithms are based on relative and absolute tolerances and should
agree for the most part, but they do have meaningful differences:

- ``math.isclose(a, b, rel_tol=1e-9, abs_tol=0.0)``:  True if the relative
  tolerance is met w.r.t. either ``a`` or ``b`` or if the absolute
  tolerance is met.  Because the relative tolerance is calculated w.r.t.
  both ``a`` and ``b``, this test is symmetric (i.e.  neither ``a`` nor
  ``b`` is a "reference value").  You have to specify an absolute tolerance
  if you want to compare to ``0.0`` because there is no tolerance by
  default.  Only available in python>=3.5.  `More information...`__

  __ https://docs.python.org/3/library/math.html#math.isclose

- ``numpy.isclose(a, b, rtol=1e-5, atol=1e-8)``: True if the difference
  between ``a`` and ``b`` is less that the sum of the relative tolerance
  w.r.t. ``b`` and the absolute tolerance.  Because the relative tolerance
  is only calculated w.r.t. ``b``, this test is asymmetric and you can
  think of ``b`` as the reference value.  Support for comparing sequences
  is provided by ``numpy.allclose``.  `More information...`__

  __ http://docs.scipy.org/doc/numpy-1.10.0/reference/generated/numpy.isclose.html

- ``unittest.TestCase.assertAlmostEqual(a, b)``: True if ``a`` and ``b``
  are within an absolute tolerance of ``1e-7``.  No relative tolerance is
  considered and the absolute tolerance cannot be changed, so this function
  is not appropriate for very large or very small numbers.  Also, it's only
  available in subclasses of ``unittest.TestCase`` and it's ugly because it
  doesn't follow PEP8.  `More information...`__

  __ https://docs.python.org/3/library/unittest.html#unittest.TestCase.assertAlmostEqual

- ``a == pytest.approx(b, rel=1e-6, abs=1e-12)``: True if the relative
  tolerance is met w.r.t. ``b`` or if the absolute tolerance is met.
  Because the relative tolerance is only calculated w.r.t. ``b``, this test
  is asymmetric and you can think of ``b`` as the reference value.  In the
  special case that you explicitly specify an absolute tolerance but not a
  relative tolerance, only the absolute tolerance is considered.

.. warning::

   .. versionchanged:: 3.2

   In order to avoid inconsistent behavior, ``TypeError`` is
   raised for ``>``, ``>=``, ``<`` and ``<=`` comparisons.
   The example below illustrates the problem::

       assert approx(0.1) > 0.1 + 1e-10  # calls approx(0.1).__gt__(0.1 + 1e-10)
       assert 0.1 + 1e-10 > approx(0.1)  # calls approx(0.1).__lt__(0.1 + 1e-10)

   In the second example one expects ``approx(0.1).__le__(0.1 + 1e-10)``
   to be called. But instead, ``approx(0.1).__lt__(0.1 + 1e-10)`` is used to
   comparison. This is because the call hierarchy of rich comparisons
   follows a fixed behavior. `More information...`__

   __ https://docs.python.org/3/reference/datamodel.html#object.__ge__