Esempio n. 1
0
def _welford():
    """Welford's method of calculating the running variance.

    Consume values and return running estimates of (n, M2) where:
        n = number of data points seen so far
        M2 = the second moment about the mean
           = sum( (x-m)**2 ) where m = mean of the x seen so far.

    """
    # Note: for better results, use this on the residues (x - m) instead
    # of the raw x values, where m equals the mean of the data.
    M2_partials = []
    x = (yield None)
    m = x  # First estimate of the mean is the first value.
    n = 1
    while True:
        delta = x - m
        m += delta/n  # Update the mean.
        stats.add_partial(delta*(x-m), M2_partials)  # Update the 2nd moment.
        M2 = _sum(M2_partials)
        assert M2 >= 0.0
        x = (yield (n, M2))
        n += 1
Esempio n. 2
0
 def value(self):
     return _sum(self.partials)
Esempio n. 3
0
def sum(data, start=0):
    """sum(data [, start]) -> value

    Return a high-precision sum of the given numeric data. If optional
    argument ``start`` is given, it is added to the total. If ``data`` is
    empty, ``start`` (defaulting to 0) is returned.


    Examples
    --------

    >>> sum([3, 2.25, 4.5, -0.5, 1.0], 0.75)
    11.0

    Float sums are calculated using high-precision floating point arithmetic
    that can avoid some sources of round-off error:

    >>> sum([1e50, 1, -1e50] * 1000)  # Built-in sum returns zero.
    1000.0

    Fractions and Decimals are also supported:

    >>> from fractions import Fraction as F
    >>> sum([F(2, 3), F(7, 5), F(1, 4), F(5, 6)])
    Fraction(63, 20)

    Decimal sums honour the context:

    >>> import decimal
    >>> D = decimal.Decimal
    >>> data = [D("0.1375"), D("0.2108"), D("0.3061"), D("0.0419")]
    >>> sum(data)
    Decimal('0.6963')
    >>> with decimal.localcontext(
    ...         decimal.Context(prec=2, rounding=decimal.ROUND_DOWN)):
    ...     sum(data)
    Decimal('0.68')


    Limitations
    -----------

    ``sum`` supports mixed arithmetic with the following limitations:

    - mixing Fractions and Decimals raises TypeError;
    - mixing floats with either Fractions or Decimals coerces to float,
      which may lose precision;
    - complex numbers are not supported.

    These limitations may change without notice in future versions.

    """
    if not isinstance(start, numbers.Number):
        raise TypeError('sum only accepts numbers')
    total = start
    data = iter(data)
    x = None
    if not isinstance(total, float):
        # Non-float sum. If we find a float, we exit this loop and continue
        # with the float code below. Until that happens, we keep adding.
        for x in data:
            if isinstance(x, float):
                # Convert running total to a float. See comment below for
                # why we do it this way.
                total = type(total).__float__(total)
                break
            total += x
        else:
            # No break, so we're done.
            return total
    # High-precision float sum.
    assert isinstance(total, float)
    partials = []
    add_partial(total, partials)
    if x is not None:
        add_partial(x, partials)
    for x in data:
        try:
            # Don't call float() directly, as that converts strings and we
            # don't want that. Also, like all dunder methods, we should call
            # __float__ on the class, not the instance.
            x = type(x).__float__(x)
        except OverflowError:
            x = float('inf') if x > 0 else float('-inf')
        add_partial(x, partials)
    return _sum(partials)