# unable to coerce <type 'sage.rings.real_mpfi.RealIntervalFieldElement'> to an integer

I am very desperate. I just want to convert a real number to an integer. I have tried int(x), Integer(x), floor(x), ceil(x) but nothing seems to work.

edit retag close merge delete

Both floor and ceil work for me. (Although this is no coercion, rather a forced push.)

sage: import random
sage: a = random.uniform( 10**5,10**9 )
sage: a
595085086.3412846
sage: floor(a)
595085086
sage: type( floor(a) )
<type 'sage.rings.integer.Integer'>
sage: floor(a).factor()
2 * 297542543
sage: ceil(a)
595085087
sage: ceil(a).factor()
5437 * 109451


As seen, the type of the floored a is a "sage integer", it has for instance the method factor.

Please provide code that fails for floor and/or ceil.

How to create an instance of that ...RealIntervalFieldElement type? (And this is no real number...)

( 2017-07-21 04:04:34 -0500 )edit

Sort by » oldest newest most voted

If you want a more precise help, you need to provide your code (e.g. what is the precision of the number you are considering).

RealIntervalField elements are pairs of floating-point numbers representing an interval where the actual value is supposed to live. Such a representation is used to do numerical computations wile guaranteeing the error.

Since ZZ is an exact ring, it is not safe to transform such an interval into an integer, unless the two endpoints are equal and correspond to an integer (which could be implemented by the way).

The dirty way is to first transform your real interval element into a floating-point number, and then into an integer, for example:

sage: a = RIF(4)
sage: ZZ(RR(a))
4


Note however, the map from RIF to RR just takes the middle of the two endpoints:

sage: a = RIF(0,1)
sage: a
1.?
sage: a.endpoints()
(0.000000000000000, 1.00000000000000)
sage: RR(a)
0.500000000000000


Hence it can be dangerous:

sage: a = RIF(0,10)
sage: ZZ(RR(a))
5

sage: a = RIF(pi)
sage: b = RIF(3+pi)
sage: c = b-a
sage: c.endpoints()
(2.99999999999999, 3.00000000000001)
sage: c.center()
3.00000000000000
sage: c.center() in ZZ
True
sage: ZZ(RR(c))
3


(you could hence imagine situations where the center is an integer by chance while the represented number is not an integer, just close to one).

The only safe way to convert from RIF to ZZ is to first check that the endpoints are equal and in this case return it as an integer if it is an integer, something like:

sage: def intify(r):
....:     if r.is_exact():
....:         c = r.center()
....:         if c in ZZ:
....:             return ZZ(c)
....:         else:
....:             raise ValueError('The interval is exact but not an integer.')
....:     else:
....:         raise ValueError('The interval is not exact.')
sage: intify(RIF(2))
2
sage: intify(RIF(sqrt(2))*RIF(sqrt(2)))
ValueError: The interval is not exact.
sage: intify(RIF(0.5))
ValueError: The interval is exact but not an integer.
sage: intify(RIF(0,1))
ValueError: The interval is not exact.

more

Please note that we get errors for ZZ( RR( a ) ) when a "has a fractional part":

sage: a = RIF(4)
sage: ZZ( RR( a ) )
4
sage: try:    a = ZZ( RR( RIF( pi ) ) )
....: except TypeError:    print "TypeError!"
....:
TypeError!


Also:

sage: try:    print ZZ( RR( RIF( 0, 9 ) ) )
....: except TypeError:    print "TypeError!"
....:
TypeError!
sage: try:    print ZZ( RR( RIF( 0, 10 ) ) )
....: except TypeError:    print "TypeError!"
....:
5

( 2017-07-21 11:30:36 -0500 )edit

A real interval field element is a pair of real numbers (lower and upper)

sage: a = RIF(pi)
sage: a.lower()
3.14159265358979
sage: a.upper()
3.14159265358980
sage: b = RIF(3.24, 5.4)
sage: b.lower()
3.24000000000000
sage: b.upper()
5.40000000000001


You can see above that the interval is not necessarily small! And you can check that applying floor not necessarily leads to a unique possibility

sage: b.floor()
4.?
sage: b.floor().lower()
3.00000000000000
sage: b.floor().upper()
5.00000000000000


If you want to go from a real interval field to an integer there are the following methods

sage: a.unique_floor()
3
sage: a.unique_ceil()
4
sage: c = RIF(2.9, 3.1)
sage: c.unique_integer()
3


These methods might give errors when not appropriate

sage: a.unique_integer()
Traceback (most recent call last):
...
ValueError: interval contains no integer
sage: b.unique_floor()
Traceback (most recent call last):
...
ValueError: interval does not have a unique floor

more

I think, the problem occurs as in the following case:

sage: a = RIF( pi^3 )
sage: a
31.0062766802999?
sage: floor(a), type(floor(a))
(31, <type 'sage.rings.real_mpfi.RealIntervalFieldElement'>)
sage: ceil(a), type(ceil(a))
(32, <type 'sage.rings.real_mpfi.RealIntervalFieldElement'>)


and the two methods work, but still do not leave the encapsulation, so no real number is provided. If this is the problem, then note that the "interval instance" a has a lower and an upper method, which leave the class, offer real numbers, where we can apply as desired floor and ceil... For instance:

sage: a = RIF( pi^3 )
sage: a
31.0062766802999?

sage: a.lower(), type( a.lower() )
(31.0062766802998, <type 'sage.rings.real_mpfr.RealNumber'>)
sage: floor( a.lower() ), type( floor( a.lower() ) )
(31, <type 'sage.rings.integer.Integer'>)
sage: floor( a.lower() ) . is_prime()
True

sage: a.upper(), type( a.upper() )
(31.0062766802999, <type 'sage.rings.real_mpfr.RealNumber'>)
sage: ceil( a.upper() ), type( ceil( a.upper() ) )
(32, <type 'sage.rings.integer.Integer'>)
sage: ceil( a.upper() ) . is_prime_power()
True

more