In general, real values cannot be represented exactly if the representation is explicit. As a result, they are usually approximated on computers by floating point numbers, which have a finite precision. This approximation is sufficient for most purposes; however, in some situations it can lead to significant error. Worse, there is usually nothing to indicate that the final result has significant error; this can lead to completely wrong answers being accepted as correct.
One way to deal with this is to use interval arithmetic. The basic idea is that rather than using a single floating point value to approximate the true real value, a pair of floating point bounds are used which are guaranteed to enclose the true real value. Each arithmetic operation is performed on the interval represented by these bounds, and the result rounded to ensure it encloses the true result. The result is that any uncertainty in the final result is made explicit: while the true real value of the result is still not known exactly, it is guaranteed to lie somewhere in the computed interval.
Of course, interval arithmetic is no panacea: it may be that the final interval is too wide to be useful. However this indicates that the problem was probably ill-conditioned or poorly computed: if the same computation had been performed with normal floating point numbers, the final floating point value would probably not have been near the true real value, and there would have been no indication that there might be a problem.
In ECLiPSe, such intervals are represented using the bounded real data type.
- Bounded reals are written as two floating point bounds separated by a double underscore (e.g. 1.5__2.0, 1.0__1.0, 3.1415926535897927__3.1415926535897936)
- Other numeric types can be converted to bounded reals by giving them a breal/1 wrapper, or by calling breal/2 directly
- Bounded reals are not usually entered directly by the user; normally they just occur as the results of computations
- A bounded real represents a single real number whose value is known to lie somewhere between the bounds and is uncertain only because of the limited precision with which is has been calculated
- An arithmetic operation is only performed using bounded reals if at least one of its arguments is a bounded real
An example of using bounded reals to safely compute the square root of 2:
?- X is sqrt(breal(2)). X = 1.4142135623730949__1.4142135623730954 Yes
To see how using ordinary floating point numbers can lead to inaccuracy, try dividing 1 by 10, and then adding it together 10 times. Using floats the result is not 1.0; using bounded reals the computed interval contains 1.0 and gives an indication of how much potential error there is:
?- Y is float(1) / 10, X is Y + Y + Y + Y + Y + Y + Y + Y + Y + Y. X = 0.99999999999999989 Y = 0.1 Yes ?- Y is breal(1) / 10, X is Y + Y + Y + Y + Y + Y + Y + Y + Y + Y. X = 0.99999999999999978__1.0000000000000007 Y = 0.099999999999999992__0.1 Yes