Example #1
0
def _round(x, y):
    # Python 3 uses "banker's rounding": when a value is equidistant between
    # two rounded numbers, it rounds to the even digit. For example
    # >>> round(2.5)
    # 2
    # >>> round(3.5)
    # 4
    # >>> round(2.25, 2)
    # 2.2
    #
    # So, I've reimplemented the rounding most people expect.
    #
    # Either way, imprecision effects come into play. With either rounding,
    # one would expect round(2.675, 2) to be 2.68, but 2.675 is stored as
    # something slightly smaller than 2.675, so it rounds down to 2.67.
    #
    # Stata has this latter issue as well, depending on use. If you use 
    # round(2.675, 0.01) interactively, you'll get 2.68. If you use
    # round(x, 0.01) where x is a variable containing 2.675 (approx), then
    # you get 2.67. If you use round(x, y) where x is a variable containing
    # 2.675 (approx) and y is a variable containing 0.01 (approx), then you
    # get 2.68 (approx).
    #
    # . di round(2.675, 0.01)
    # 2.68
    # 
    # . clear
    # 
    # . set obs 1
    # obs was 0, now 1
    # 
    # . gen x = 2.675
    # 
    # . di round(x, 0.01)
    # 2.67
    #
    # . clear
    # 
    # . set obs 1
    # obs was 0, now 1
    # 
    # . gen x = 2.675
    # 
    # . gen y = 0.01
    # 
    # . di round(x, y)
    # 2.6799999
    #

    if _is_missing(y):
        return mv
    if y == 0:
        if _is_missing(x) and not isinstance(x, MissingValue):
            return get_missing(x)
        return x
    if _is_missing(x):
        return x if isinstance(x, MissingValue) else get_missing(x)
    return math.floor(x / y + 0.5) * y
Example #2
0
def _round(x, y):
    # Python 3 uses "banker's rounding": when a value is equidistant between
    # two rounded numbers, it rounds to the even digit. For example
    # >>> round(2.5)
    # 2
    # >>> round(3.5)
    # 4
    # >>> round(2.25, 2)
    # 2.2
    #
    # So, I've reimplemented the rounding most people expect.
    #
    # Either way, imprecision effects come into play. With either rounding,
    # one would expect round(2.675, 2) to be 2.68, but 2.675 is stored as
    # something slightly smaller than 2.675, so it rounds down to 2.67.
    #
    # Stata has this latter issue as well, depending on use. If you use
    # round(2.675, 0.01) interactively, you'll get 2.68. If you use
    # round(x, 0.01) where x is a variable containing 2.675 (approx), then
    # you get 2.67. If you use round(x, y) where x is a variable containing
    # 2.675 (approx) and y is a variable containing 0.01 (approx), then you
    # get 2.68 (approx).
    #
    # . di round(2.675, 0.01)
    # 2.68
    #
    # . clear
    #
    # . set obs 1
    # obs was 0, now 1
    #
    # . gen x = 2.675
    #
    # . di round(x, 0.01)
    # 2.67
    #
    # . clear
    #
    # . set obs 1
    # obs was 0, now 1
    #
    # . gen x = 2.675
    #
    # . gen y = 0.01
    #
    # . di round(x, y)
    # 2.6799999
    #

    if _is_missing(y):
        return mv
    if y == 0:
        if _is_missing(x) and not isinstance(x, MissingValue):
            return get_missing(x)
        return x
    if _is_missing(x):
        return x if isinstance(x, MissingValue) else get_missing(x)
    return math.floor(x / y + 0.5) * y
Example #3
0
def _reldif(x, y):
    missing = False
    if x is None or (not isinstance(x, MissingValue) and 
            (x < -8.988465674311579e+307 or x > 8.988465674311579e+307)):
        x = get_missing(x)
        missing = True
    if y is None or (not isinstance(y, MissingValue) and 
            (y < -8.988465674311579e+307 or y > 8.988465674311579e+307)):
        y = get_missing(y)
        missing = True
    if x == y:
        return 0
    if missing:
        return mv
    return abs(x - y) / (abs(y) + 1)
Example #4
0
def _reldif(x, y):
    missing = False
    if x is None or (not isinstance(x, MissingValue) and
                     (x < -8.988465674311579e+307
                      or x > 8.988465674311579e+307)):
        x = get_missing(x)
        missing = True
    if y is None or (not isinstance(y, MissingValue) and
                     (y < -8.988465674311579e+307
                      or y > 8.988465674311579e+307)):
        y = get_missing(y)
        missing = True
    if x == y:
        return 0
    if missing:
        return mv
    return abs(x - y) / (abs(y) + 1)
Example #5
0
def _int(x):
    if isinstance(x, MissingValue):
        return x
    if x is None:
        return mv
    if not isinstance(x, int) and not isinstance(x, float):
        raise TypeError("int, float, or MissingValue instance required")
    if not -8.988465674311579e+307 <= x <= 8.988465674311579e+307:
        return get_missing(x)
    return int(x)
Example #6
0
def _int(x):
    if isinstance(x, MissingValue):
        return x
    if x is None:
        return mv
    if not isinstance(x, int) and not isinstance(x, float):
        raise TypeError("int, float, or MissingValue instance required")
    if not -8.988465674311579e+307 <= x <= 8.988465674311579e+307:
        return get_missing(x)
    return int(x)
Example #7
0
def st_round(x, y=1):
    """Rounding function.
    
    Parameters
    ----------
    x : float, int, MissingValue instance, or None
    y : float, int, MissingValue instance, or None;
        y is optional, default value is 1
    
    Returns
    -------
    If both x and y are non-missing, returns x / y rounded to
        the nearest integer times y (but see notes below).
    If y is 1 or y is not specified, returns x rounded to the 
        nearest integer (but see notes below).
    If y is zero, returns x.
    If y is missing, MISSING (".") is returned.
    If x is missing and y is non-missing, returns MissingValue
        corresponding to x.
    If both x and y are missing, returns MISSING (".").
    
    Notes
    -----
    Though Python 3 uses "banker's rounding" or "round half to even",
    this function uses "round half up". For example, with Python 3's
    `round` function, `round(3.5)` and `round(4.5)` are both 4, but
    `st_round(3.5)` is 4 and `st_round(4.5)` is 5.
    
    Keep in mind that floating point imprecision of inputs may affect
    the output.
    
    """
    if isinstance(x, StataVarVals):
        if isinstance(y, StataVarVals):
            return StataVarVals([
                _round(vx, vy) for vx, vy in zip(x.values, y.values)
            ])
        if y == 0:
            return StataVarVals([
                get_missing(v)
                if _is_missing(v) and not isinstance(v, MissingValue)
                else v for v in x.values
            ])
        else:
            return StataVarVals([
                _round(v, y) for v in x.values
            ])
    if isinstance(y, StataVarVals):
        return StataVarVals([
            _round(x, v) for v in y.values
        ])
    return _round(x, y)
Example #8
0
def st_round(x, y=1):
    """Rounding function.
    
    Parameters
    ----------
    x : float, int, MissingValue instance, or None
    y : float, int, MissingValue instance, or None;
        y is optional, default value is 1
    
    Returns
    -------
    If both x and y are non-missing, returns x / y rounded to
        the nearest integer times y (but see notes below).
    If y is 1 or y is not specified, returns x rounded to the 
        nearest integer (but see notes below).
    If y is zero, returns x.
    If y is missing, MISSING (".") is returned.
    If x is missing and y is non-missing, returns MissingValue
        corresponding to x.
    If both x and y are missing, returns MISSING (".").
    
    Notes
    -----
    Though Python 3 uses "banker's rounding" or "round half to even",
    this function uses "round half up". For example, with Python 3's
    `round` function, `round(3.5)` and `round(4.5)` are both 4, but
    `st_round(3.5)` is 4 and `st_round(4.5)` is 5.
    
    Keep in mind that floating point imprecision of inputs may affect
    the output.
    
    """
    if isinstance(x, StataVarVals):
        if isinstance(y, StataVarVals):
            return StataVarVals(
                [_round(vx, vy) for vx, vy in zip(x.values, y.values)])
        if y == 0:
            return StataVarVals([
                get_missing(v)
                if _is_missing(v) and not isinstance(v, MissingValue) else v
                for v in x.values
            ])
        else:
            return StataVarVals([_round(v, y) for v in x.values])
    if isinstance(y, StataVarVals):
        return StataVarVals([_round(x, v) for v in y.values])
    return _round(x, y)