From 6b46762974bb281106088dae124ca0059571db2a Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Sat, 15 Mar 2008 20:02:04 +0000 Subject: Removed Exact/Inexact after discussion with Yasskin. Unlike Scheme where exactness is implemented as taints, the Python implementation associated exactness with data types. This created inheritance issues (making an exact subclass of floats would result in the subclass having both an explicit Exact registration and an inherited Inexact registration). This was a problem for the decimal module which was designed to span both exact and inexact arithmetic. There was also a question of use cases and no examples were found where ABCs for exactness could be used to improve code. One other issue was having separate tags for both the affirmative and negative cases. This is at odds with the approach taken elsewhere in the Python (i.e. we don't have an ABC both Hashable and Unhashable). --- Lib/numbers.py | 58 +++------------------------------------ Lib/test/test_abstract_numbers.py | 9 ------ 2 files changed, 4 insertions(+), 63 deletions(-) diff --git a/Lib/numbers.py b/Lib/numbers.py index b6de8ac..7fb61b0 100644 --- a/Lib/numbers.py +++ b/Lib/numbers.py @@ -8,10 +8,7 @@ TODO: Fill out more detailed documentation on the operators.""" from __future__ import division from abc import ABCMeta, abstractmethod, abstractproperty -__all__ = ["Number", "Exact", "Inexact", - "Complex", "Real", "Rational", "Integral", - ] - +__all__ = ["Number", "Complex", "Real", "Rational", "Integral"] class Number(object): """All numbers inherit from this class. @@ -22,60 +19,13 @@ class Number(object): __metaclass__ = ABCMeta -class Exact(Number): - """Operations on instances of this type are exact. - - As long as the result of a homogenous operation is of the same - type, you can assume that it was computed exactly, and there are - no round-off errors. Laws like commutativity and associativity - hold. - """ - -Exact.register(int) -Exact.register(long) - - -class Inexact(Number): - """Operations on instances of this type are inexact. - - Given X, an instance of Inexact, it is possible that (X + -X) + 3 - == 3, but X + (-X + 3) == 0. The exact form this error takes will - vary by type, but it's generally unsafe to compare this type for - equality. - """ - -Inexact.register(complex) -Inexact.register(float) -# Inexact.register(decimal.Decimal) - - ## Notes on Decimal ## ---------------- ## Decimal has all of the methods specified by the Real abc, but it should ## not be registered as a Real because decimals do not interoperate with -## binary floats. -## -## Decimal has some of the characteristics of Integrals. It provides -## logical operations but not as operators. The logical operations only apply -## to a subset of decimals (those that are non-negative, have a zero exponent, -## and have digits that are only 0 or 1). It does provide __long__() and -## a three argument form of __pow__ that includes exactness guarantees. -## It does not provide an __index__() method. -## -## Depending on context, decimal operations may be exact or inexact. -## -## When decimal is run in a context with small precision and automatic rounding, -## it is Inexact. See the "Floating point notes" section of the decimal docs -## for an example of losing the associative and distributive properties of -## addition. -## -## When decimal is used for high precision integer arithmetic, it is Exact. -## When the decimal used as fixed-point, it is Exact. -## When it is run with sufficient precision, it is Exact. -## When the decimal.Inexact trap is set, decimal operations are Exact. -## For an example, see the float_to_decimal() recipe in the "Decimal FAQ" -## section of the docs -- it shows an how traps are used in conjunction -## with variable precision to reliably achieve exact results. +## binary floats (i.e. Decimal('3.14') + 2.71828 is undefined). But, +## abstract reals are expected to interoperate (i.e. R1 + R2 should be +## expected to work if R1 and R2 are both Reals). class Complex(Number): """Complex defines the operations that work on the builtin complex type. diff --git a/Lib/test/test_abstract_numbers.py b/Lib/test/test_abstract_numbers.py index 0c1f28d..034fb52 100644 --- a/Lib/test/test_abstract_numbers.py +++ b/Lib/test/test_abstract_numbers.py @@ -4,7 +4,6 @@ import math import operator import unittest from numbers import Complex, Real, Rational, Integral -from numbers import Exact, Inexact from numbers import Number from test import test_support @@ -12,8 +11,6 @@ class TestNumbers(unittest.TestCase): def test_int(self): self.failUnless(issubclass(int, Integral)) self.failUnless(issubclass(int, Complex)) - self.failUnless(issubclass(int, Exact)) - self.failIf(issubclass(int, Inexact)) self.assertEqual(7, int(7).real) self.assertEqual(0, int(7).imag) @@ -24,8 +21,6 @@ class TestNumbers(unittest.TestCase): def test_long(self): self.failUnless(issubclass(long, Integral)) self.failUnless(issubclass(long, Complex)) - self.failUnless(issubclass(long, Exact)) - self.failIf(issubclass(long, Inexact)) self.assertEqual(7, long(7).real) self.assertEqual(0, long(7).imag) @@ -36,8 +31,6 @@ class TestNumbers(unittest.TestCase): def test_float(self): self.failIf(issubclass(float, Rational)) self.failUnless(issubclass(float, Real)) - self.failIf(issubclass(float, Exact)) - self.failUnless(issubclass(float, Inexact)) self.assertEqual(7.3, float(7.3).real) self.assertEqual(0, float(7.3).imag) @@ -46,8 +39,6 @@ class TestNumbers(unittest.TestCase): def test_complex(self): self.failIf(issubclass(complex, Real)) self.failUnless(issubclass(complex, Complex)) - self.failIf(issubclass(complex, Exact)) - self.failUnless(issubclass(complex, Inexact)) c1, c2 = complex(3, 2), complex(4,1) # XXX: This is not ideal, but see the comment in math_trunc(). -- cgit v0.12