def test_two_sum_simple(): with decimal.localcontext(decimal.Context(prec=40)): i, f = 65536, 3.637978807091714e-12 a = Decimal(i) + Decimal(f) s, r = two_sum(i, f) b = Decimal(s) + Decimal(r) assert (abs(a - b) * u.day).to(u.ns) < 1 * u.ns
def day_frac(val1, val2, factor=None, divisor=None): """Return the sum of ``val1`` and ``val2`` as two float64s. The returned floats are an integer part and the fractional remainder, with the latter guaranteed to be within -0.5 and 0.5 (inclusive on either side, as the integer is rounded to even). The arithmetic is all done with exact floating point operations so no precision is lost to rounding error. It is assumed the sum is less than about 1e16, otherwise the remainder will be greater than 1.0. Parameters ---------- val1, val2 : array of float Values to be summed. factor : float, optional If given, multiply the sum by it. divisor : float, optional If given, divide the sum by it. Returns ------- day, frac : float64 Integer and fractional part of val1 + val2. """ # Note that the version of astropy >=3.2; # See https://github.com/astropy/astropy/pull/8763 # TODO: remove when we only support astropy >=3.2. # # Add val1 and val2 exactly, returning the result as two float64s. # The first is the approximate sum (with some floating point error) # and the second is the error of the float64 sum. sum12, err12 = two_sum(val1, val2) if factor is not None: sum12, carry = two_product(sum12, factor) carry += err12 * factor sum12, err12 = two_sum(sum12, carry) if divisor is not None: q1 = sum12 / divisor p1, p2 = two_product(q1, divisor) d1, d2 = two_sum(sum12, -p1) d2 += err12 d2 -= p2 q2 = (d1 + d2) / divisor # 3-part float fine here; nothing can be lost sum12, err12 = two_sum(q1, q2) # get integer fraction day = np.around(sum12) extra, frac = two_sum(sum12, -day) frac += extra + err12 # This part was missed in astropy... excess = np.around(frac) day += excess extra, frac = two_sum(sum12, -day) frac += extra + err12 return day, frac
def test_two_sum_size(f1, f2): r1, r2 = two_sum(f1, f2) assert (abs(r1) > abs(r2) / np.finfo(float).eps or r1 == r2 == 0 or not np.isfinite(f1 + f2))
def test_two_sum_symmetric(f1, f2): np.testing.assert_equal(two_sum(f1, f2), two_sum(f2, f1))
def test_two_sum(i, f): with decimal.localcontext(decimal.Context(prec=40)): a = Decimal(i) + Decimal(f) s, r = two_sum(i, f) b = Decimal(s) + Decimal(r) assert_almost_equal(a, b, atol=Decimal(tiny), rtol=Decimal(0))