# Incorrect results for comparison expression

Sage incorrectly evaluates bool(1/47749 <= -5564456128*e + 15125759978) as False.

In more detail, consider this:

sage: x = -5564456128*e + 15125759978
sage: (1/47749).n(digits=6)
0.0000209428
sage: x.n(digits=20)
0.000020943072740919888020
sage: bool(1/47749 <= x)
False


What is going on? Why does the last boolean evaluate to False? This results in the failure of the assertion that 1/ceil(1/x) <= x, which should be true mathematically.

Is there a way to compare two quantities that will result in a correct answer, using as much precision as necessary?

edit retag close merge delete

Incidentally, x.n(digits=6) instead of giving something like 0.0000209431 gives 1024.00, which is scary.

Sort by » oldest newest most voted

FWIW :

sage: x = -5564456128*e + 15125759978
sage: (x-1/47749).n(digits=50)
2.2327547500435249115043756744718383299006623385945e-10


As usual, stay exact as long as possible... The chapters of this book dedicated to numerical computation may enlighten you...

Note that a "visual" comparison based on :

sage: "%8.6g, %8.6g"%(x,1/47749)
'2.09808e-05, 2.09428e-05'


misses the target by about two magnitude orders (implying a difference of about 4e-8...).

Note also that :

sage: (x-1/47749).is_zero()
False
sage: (x-1/47749).is_positive()
False
sage: (x-1/47749).is_negative()
False


which is surprising, but conformant to the definitions of the methods : nothoing is known nor deducible about these quantities, and only numerical computation of their differences allows to answer the question.

more

Doesn't bool(1/47749 <= -5564456128*e + 15125759978) satisfy your recommendation to "stay exact as long as possible"? The question is how to perform the comparison in a way that gives a correct answer.

For some reason, (x-1/47749).is_zero()gives True for me… (Sage 8.3 which is a couple of years old, but also tried it on CoCalc Instant SageWorksheet linked from sagemath.org).

I found a work-around in a question I had myself asked about 5 years ago (but apparently forgotten its lesson): "Incorrect result for comparison (precision issues?)" at ask.sagemath.org/question/32371 — the solution is to avoid the "<" operator for comparison (what a gotcha!), and define one's own smaller function:

def smaller(a, b):
'''Returns True if a < b (and False if b < a). Assumes that a != b.'''
prec = 53
while prec < 100000:
R = RealIntervalField(prec)
try:
R(a).intersection(R(b))
except ValueError:
return R(a) < R(b)
else:
#print '{} bits of precision is not enough'.format(prec)
prec += prec // 10
raise Exception('100000 bits of precision was not enough for comparing: ', a, b, ' -- Possibly they are equal')


Then it works correctly:

sage: bool(smaller(1/47749, -5564456128*e + 15125759978))
True


Note that this function assumes that a ≠ b:

sage: smaller(pi/4, 4*arctan(1/5) - arctan(1/239))
...
Exception: ('100000 bits of precision was not enough for comparing: ', 1/4*pi, 4*arctan(1/5) - arctan(1/239), ' -- Possibly they are equal')

more

Here's the earlier question: https://ask.sagemath.org/question/323... — I can't post it as a link from the account that asked the question, it's a new account with not enough karma, and I can't find a way to merge the accounts.

Clever use of RIF... But you may want to catch the case where a and bare equal (possibly by trying (a-b).is_zero()). What does your function return when applied to John Machin's incredible formula ?

Unfortunately the Sage versions I have access to will all happily declare a and b to be equal even when they are not (see comments under your answer), so the best I could do was to add an assumption to the function that they are not equal.