Major change in the internal structure of the Decimal
number: now it does not store the mantissa as a tuple
of numbers, but as a string.

This avoids a lot of conversions, and achieves a
speedup of 40%. The API remains intact.

Thanks Mark Dickinson.
diff --git a/Lib/decimal.py b/Lib/decimal.py
index 45ecf88..6a3ee84 100644
--- a/Lib/decimal.py
+++ b/Lib/decimal.py
@@ -214,10 +214,10 @@
     def handle(self, context, *args):
         if args:
             if args[0] == 1:  # sNaN, must drop 's' but keep diagnostics
-                ans = Decimal((args[1]._sign, args[1]._int, 'n'))
+                ans = _dec_from_triple(args[1]._sign, args[1]._int, 'n', True)
                 return ans._fix_nan(context)
             elif args[0] == 2:
-                return Decimal( (args[1], args[2], 'n') )
+                return _dec_from_triple(args[1], args[2], 'n', True)
         return NaN
 
 
@@ -350,13 +350,13 @@
         if sign == 0:
             if context.rounding == ROUND_CEILING:
                 return Infsign[sign]
-            return Decimal((sign, (9,)*context.prec,
-                            context.Emax-context.prec+1))
+            return _dec_from_triple(sign, '9'*context.prec,
+                            context.Emax-context.prec+1)
         if sign == 1:
             if context.rounding == ROUND_FLOOR:
                 return Infsign[sign]
-            return Decimal( (sign, (9,)*context.prec,
-                             context.Emax-context.prec+1))
+            return _dec_from_triple(sign, '9'*context.prec,
+                             context.Emax-context.prec+1)
 
 
 class Underflow(Inexact, Rounded, Subnormal):
@@ -531,13 +531,21 @@
         Decimal("314")
         """
 
+        # Note that the coefficient, self._int, is actually stored as
+        # a string rather than as a tuple of digits.  This speeds up
+        # the "digits to integer" and "integer to digits" conversions
+        # that are used in almost every arithmetic operation on
+        # Decimals.  This is an internal detail: the as_tuple function
+        # and the Decimal constructor still deal with tuples of
+        # digits.
+
         self = object.__new__(cls)
         self._is_special = False
 
         # From an internal working value
         if isinstance(value, _WorkRep):
             self._sign = value.sign
-            self._int = tuple(map(int, str(value.int)))
+            self._int = str(value.int)
             self._exp = int(value.exp)
             return self
 
@@ -556,7 +564,7 @@
             else:
                 self._sign = 1
             self._exp = 0
-            self._int = tuple(map(int, str(abs(value))))
+            self._int = str(abs(value))
             return self
 
         # tuple/list conversion (possibly from as_tuple())
@@ -573,7 +581,7 @@
             self._sign = value[0]
             if value[2] == 'F':
                 # infinity: value[1] is ignored
-                self._int = (0,)
+                self._int = '0'
                 self._exp = value[2]
                 self._is_special = True
             else:
@@ -590,12 +598,12 @@
                                          "0 through 9.")
                 if value[2] in ('n', 'N'):
                     # NaN: digits form the diagnostic
-                    self._int = tuple(digits)
+                    self._int = ''.join(map(str, digits))
                     self._exp = value[2]
                     self._is_special = True
                 elif isinstance(value[2], (int, long)):
                     # finite number: digits give the coefficient
-                    self._int = tuple(digits or [0])
+                    self._int = ''.join(map(str, digits or [0]))
                     self._exp = value[2]
                     self._is_special = False
                 else:
@@ -608,38 +616,46 @@
             raise TypeError("Cannot convert float to Decimal.  " +
                             "First convert the float to a string")
 
-        # Other argument types may require the context during interpretation
-        if context is None:
-            context = getcontext()
-
         # From a string
         # REs insist on real strings, so we can too.
         if isinstance(value, basestring):
-            if _isinfinity(value):
-                self._exp = 'F'
-                self._int = (0,)
-                self._is_special = True
-                if _isinfinity(value) == 1:
-                    self._sign = 0
-                else:
-                    self._sign = 1
-                return self
-            if _isnan(value):
-                sig, sign, diag = _isnan(value)
-                self._is_special = True
-                if sig == 1:
-                    self._exp = 'n'  # qNaN
-                else:  # sig == 2
-                    self._exp = 'N'  # sNaN
-                self._sign = sign
-                self._int = tuple(map(int, diag))  # Diagnostic info
-                return self
-            try:
-                self._sign, self._int, self._exp = _string2exact(value)
-            except ValueError:
-                self._is_special = True
+            m = _parser(value)
+            if m is None:
+                if context is None:
+                    context = getcontext()
                 return context._raise_error(ConversionSyntax,
-                                   "Invalid literal for Decimal: %r" % value)
+                                "Invalid literal for Decimal: %r" % value)
+
+            if m.group('sign') == "-":
+                self._sign = 1
+            else:
+                self._sign = 0
+            intpart = m.group('int')
+            if intpart is not None:
+                # finite number
+                fracpart = m.group('frac')
+                exp = int(m.group('exp') or '0')
+                if fracpart is not None:
+                    self._int = (intpart+fracpart).lstrip('0') or '0'
+                    self._exp = exp - len(fracpart)
+                else:
+                    self._int = intpart.lstrip('0') or '0'
+                    self._exp = exp
+                self._is_special = False
+            else:
+                diag = m.group('diag')
+                if diag is not None:
+                    # NaN
+                    self._int = diag.lstrip('0')
+                    if m.group('signal'):
+                        self._exp = 'N'
+                    else:
+                        self._exp = 'n'
+                else:
+                    # infinity
+                    self._int = '0'
+                    self._exp = 'F'
+                self._is_special = True
             return self
 
         raise TypeError("Cannot convert %r to Decimal" % value)
@@ -709,7 +725,7 @@
 
         NaNs and infinities are considered nonzero.
         """
-        return self._is_special or self._int[0] != 0
+        return self._is_special or self._int != '0'
 
     def __cmp__(self, other):
         other = _convert_other(other)
@@ -743,8 +759,8 @@
         self_adjusted = self.adjusted()
         other_adjusted = other.adjusted()
         if self_adjusted == other_adjusted:
-            self_padded = self._int + (0,)*(self._exp - other._exp)
-            other_padded = other._int + (0,)*(other._exp - self._exp)
+            self_padded = self._int + '0'*(self._exp - other._exp)
+            other_padded = other._int + '0'*(other._exp - self._exp)
             return cmp(self_padded, other_padded) * (-1)**self._sign
         elif self_adjusted > other_adjusted:
             return (-1)**self._sign
@@ -807,7 +823,7 @@
 
         To show the internals exactly as they are.
         """
-        return (self._sign, self._int, self._exp)
+        return (self._sign, tuple(map(int, self._int)), self._exp)
 
     def __repr__(self):
         """Represents the number as an instance of Decimal."""
@@ -823,10 +839,10 @@
         if self._is_special:
             if self._isnan():
                 minus = '-'*self._sign
-                if self._int == (0,):
+                if self._int == '0':
                     info = ''
                 else:
-                    info = ''.join(map(str, self._int))
+                    info = self._int
                 if self._isnan() == 2:
                     return minus + 'sNaN' + info
                 return minus + 'NaN' + info
@@ -837,7 +853,7 @@
         if context is None:
             context = getcontext()
 
-        tmp = map(str, self._int)
+        tmp = list(self._int)
         numdigits = len(self._int)
         leftdigits = self._exp + numdigits
         if eng and not self:  # self = 0eX wants 0[.0[0]]eY, not [[0]0]0eY
@@ -1010,7 +1026,7 @@
             sign = min(self._sign, other._sign)
             if negativezero:
                 sign = 1
-            ans = Decimal( (sign, (0,), exp))
+            ans = _dec_from_triple(sign, '0', exp)
             if shouldround:
                 ans = ans._fix(context)
             return ans
@@ -1035,7 +1051,7 @@
         if op1.sign != op2.sign:
             # Equal and opposite
             if op1.int == op2.int:
-                ans = Decimal((negativezero, (0,), exp))
+                ans = _dec_from_triple(negativezero, '0', exp)
                 if shouldround:
                     ans = ans._fix(context)
                 return ans
@@ -1101,7 +1117,7 @@
         For example:
         Decimal('5.624e10')._increment() == Decimal('5.625e10')
         """
-        L = list(self._int)
+        L = map(int, self._int)
         L[-1] += 1
         spot = len(L)-1
         while L[spot] == 10:
@@ -1111,7 +1127,7 @@
                 break
             L[spot-1] += 1
             spot -= 1
-        return Decimal((self._sign, L, self._exp))
+        return _dec_from_triple(self._sign, "".join(map(str, L)), self._exp)
 
     def __mul__(self, other, context=None):
         """Return self * other.
@@ -1147,20 +1163,20 @@
 
         # Special case for multiplying by zero
         if not self or not other:
-            ans = Decimal((resultsign, (0,), resultexp))
+            ans = _dec_from_triple(resultsign, '0', resultexp)
             if shouldround:
                 # Fixing in case the exponent is out of bounds
                 ans = ans._fix(context)
             return ans
 
         # Special case for multiplying by power of 10
-        if self._int == (1,):
-            ans = Decimal((resultsign, other._int, resultexp))
+        if self._int == '1':
+            ans = _dec_from_triple(resultsign, other._int, resultexp)
             if shouldround:
                 ans = ans._fix(context)
             return ans
-        if other._int == (1,):
-            ans = Decimal((resultsign, self._int, resultexp))
+        if other._int == '1':
+            ans = _dec_from_triple(resultsign, self._int, resultexp)
             if shouldround:
                 ans = ans._fix(context)
             return ans
@@ -1168,7 +1184,7 @@
         op1 = _WorkRep(self)
         op2 = _WorkRep(other)
 
-        ans = Decimal((resultsign, map(int, str(op1.int * op2.int)), resultexp))
+        ans = _dec_from_triple(resultsign, str(op1.int * op2.int), resultexp)
         if shouldround:
             ans = ans._fix(context)
 
@@ -1199,7 +1215,7 @@
 
             if other._isinfinity():
                 context._raise_error(Clamped, 'Division by infinity')
-                return Decimal((sign, (0,), context.Etiny()))
+                return _dec_from_triple(sign, '0', context.Etiny())
 
         # Special cases for zeroes
         if not other:
@@ -1231,7 +1247,7 @@
                     coeff //= 10
                     exp += 1
 
-        ans = Decimal((sign, map(int, str(coeff)), exp))
+        ans = _dec_from_triple(sign, str(coeff), exp)
         return ans._fix(context)
 
     __truediv__ = __div__
@@ -1250,7 +1266,7 @@
 
         expdiff = self.adjusted() - other.adjusted()
         if not self or other._isinfinity() or expdiff <= -2:
-            return (Decimal((sign, (0,), 0)),
+            return (_dec_from_triple(sign, '0', 0),
                     self._rescale(ideal_exp, context.rounding))
         if expdiff <= context.prec:
             op1 = _WorkRep(self)
@@ -1261,8 +1277,8 @@
                 op2.int *= 10**(op2.exp - op1.exp)
             q, r = divmod(op1.int, op2.int)
             if q < 10**context.prec:
-                return (Decimal((sign, map(int, str(q)), 0)),
-                        Decimal((self._sign, map(int, str(r)), ideal_exp)))
+                return (_dec_from_triple(sign, str(q), 0),
+                        _dec_from_triple(self._sign, str(r), ideal_exp))
 
         # Here the quotient is too large to be representable
         ans = context._raise_error(DivisionImpossible,
@@ -1391,7 +1407,7 @@
         # self = 0 -> remainder = self, with ideal exponent
         ideal_exponent = min(self._exp, other._exp)
         if not self:
-            ans = Decimal((self._sign, (0,), ideal_exponent))
+            ans = _dec_from_triple(self._sign, '0', ideal_exponent)
             return ans._fix(context)
 
         # catch most cases of large or small quotient
@@ -1428,7 +1444,7 @@
             sign = 1-sign
             r = -r
 
-        ans = Decimal((sign, map(int, str(r)), ideal_exponent))
+        ans = _dec_from_triple(sign, str(r), ideal_exponent)
         return ans._fix(context)
 
     def __floordiv__(self, other, context=None):
@@ -1480,9 +1496,9 @@
                 raise OverflowError("Cannot convert infinity to long")
         s = (-1)**self._sign
         if self._exp >= 0:
-            return s*int(''.join(map(str, self._int)))*10**self._exp
+            return s*int(self._int)*10**self._exp
         else:
-            return s*int(''.join(map(str, self._int))[:self._exp] or '0')
+            return s*int(self._int[:self._exp] or '0')
 
     def __long__(self):
         """Converts to a long.
@@ -1499,11 +1515,8 @@
         # precision-1 if _clamp=1.
         max_payload_len = context.prec - context._clamp
         if len(payload) > max_payload_len:
-            pos = len(payload)-max_payload_len
-            while pos < len(payload) and payload[pos] == 0:
-                pos += 1
-            payload = payload[pos:]
-            return Decimal((self._sign, payload, self._exp))
+            payload = payload[len(payload)-max_payload_len:].lstrip('0')
+            return _dec_from_triple(self._sign, payload, self._exp, True)
         return Decimal(self)
 
     def _fix(self, context):
@@ -1536,7 +1549,7 @@
             new_exp = min(max(self._exp, Etiny), exp_max)
             if new_exp != self._exp:
                 context._raise_error(Clamped)
-                return Decimal((self._sign, (0,), new_exp))
+                return _dec_from_triple(self._sign, '0', new_exp)
             else:
                 return Decimal(self)
 
@@ -1568,7 +1581,8 @@
                     # we get here only if rescaling rounds the
                     # cofficient up to exactly 10**context.prec
                     if ans._exp < Etop:
-                        ans = Decimal((ans._sign, ans._int[:-1], ans._exp+1))
+                        ans = _dec_from_triple(ans._sign,
+                                                   ans._int[:-1], ans._exp+1)
                     else:
                         # Inexact and Rounded have already been raised
                         ans = context._raise_error(Overflow, 'above Emax',
@@ -1578,8 +1592,8 @@
         # fold down if _clamp == 1 and self has too few digits
         if context._clamp == 1 and self._exp > Etop:
             context._raise_error(Clamped)
-            self_padded = self._int + (0,)*(self._exp - Etop)
-            return Decimal((self._sign, self_padded, Etop))
+            self_padded = self._int + '0'*(self._exp - Etop)
+            return _dec_from_triple(self._sign, self_padded, Etop)
 
         # here self was representable to begin with; return unchanged
         return Decimal(self)
@@ -1594,29 +1608,29 @@
     def _round_down(self, prec):
         """Also known as round-towards-0, truncate."""
         newexp = self._exp + len(self._int) - prec
-        return Decimal((self._sign, self._int[:prec] or (0,), newexp))
+        return _dec_from_triple(self._sign, self._int[:prec] or '0', newexp)
 
     def _round_up(self, prec):
         """Rounds away from 0."""
         newexp = self._exp + len(self._int) - prec
-        tmp = Decimal((self._sign, self._int[:prec] or (0,), newexp))
+        tmp = _dec_from_triple(self._sign, self._int[:prec] or '0', newexp)
         for digit in self._int[prec:]:
-            if digit != 0:
+            if digit != '0':
                 return tmp._increment()
         return tmp
 
     def _round_half_up(self, prec):
         """Rounds 5 up (away from 0)"""
-        if self._int[prec] >= 5:
+        if self._int[prec] in '56789':
             return self._round_up(prec)
         else:
             return self._round_down(prec)
 
     def _round_half_down(self, prec):
         """Round 5 down"""
-        if self._int[prec] == 5:
+        if self._int[prec] == '5':
             for digit in self._int[prec+1:]:
-                if digit != 0:
+                if digit != '0':
                     break
             else:
                 return self._round_down(prec)
@@ -1624,7 +1638,7 @@
 
     def _round_half_even(self, prec):
         """Round 5 to even, rest to nearest."""
-        if prec and self._int[prec-1] & 1:
+        if prec and self._int[prec-1] in '13579':
             return self._round_half_up(prec)
         else:
             return self._round_half_down(prec)
@@ -1645,7 +1659,7 @@
 
     def _round_05up(self, prec):
         """Round down unless digit prec-1 is 0 or 5."""
-        if prec == 0 or self._int[prec-1] in (0, 5):
+        if prec == 0 or self._int[prec-1] in '05':
             return self._round_up(prec)
         else:
             return self._round_down(prec)
@@ -1763,7 +1777,7 @@
             base = pow(base, 10, modulo)
         base = pow(base, exponent.int, modulo)
 
-        return Decimal((sign, map(int, str(base)), 0))
+        return _dec_from_triple(sign, str(base), 0)
 
     def _power_exact(self, other, p):
         """Attempt to compute self**other exactly.
@@ -1853,7 +1867,7 @@
                 zeros = min(exponent-ideal_exponent, p-1)
             else:
                 zeros = 0
-            return Decimal((0, (1,) + (0,)*zeros, exponent-zeros))
+            return _dec_from_triple(0, '1' + '0'*zeros, exponent-zeros)
 
         # case where y is negative: xc must be either a power
         # of 2 or a power of 5.
@@ -1914,7 +1928,7 @@
             if xc >= 10**p:
                 return None
             xe = -e-xe
-            return Decimal((0, map(int, str(xc)), xe))
+            return _dec_from_triple(0, str(xc), xe)
 
         # now y is positive; find m and n such that y = m/n
         if ye >= 0:
@@ -1976,7 +1990,7 @@
             zeros = min(xe-ideal_exponent, p-len(str_xc))
         else:
             zeros = 0
-        return Decimal((0, map(int, str_xc)+[0,]*zeros, xe-zeros))
+        return _dec_from_triple(0, str_xc+'0'*zeros, xe-zeros)
 
     def __pow__(self, other, modulo=None, context=None):
         """Return self ** other [ % modulo].
@@ -2037,12 +2051,12 @@
                     return context._raise_error(InvalidOperation,
                         'x ** y with x negative and y not an integer')
             # negate self, without doing any unwanted rounding
-            self = Decimal((0, self._int, self._exp))
+            self = self.copy_negate()
 
         # 0**(+ve or Inf)= 0; 0**(-ve or -Inf) = Infinity
         if not self:
             if other._sign == 0:
-                return Decimal((result_sign, (0,), 0))
+                return _dec_from_triple(result_sign, '0', 0)
             else:
                 return Infsign[result_sign]
 
@@ -2051,7 +2065,7 @@
             if other._sign == 0:
                 return Infsign[result_sign]
             else:
-                return Decimal((result_sign, (0,), 0))
+                return _dec_from_triple(result_sign, '0', 0)
 
         # 1**other = 1, but the choice of exponent and the flags
         # depend on the exponent of self, and on whether other is a
@@ -2078,7 +2092,7 @@
                 context._raise_error(Rounded)
                 exp = 1-context.prec
 
-            return Decimal((result_sign, (1,)+(0,)*-exp, exp))
+            return _dec_from_triple(result_sign, '1'+'0'*-exp, exp)
 
         # compute adjusted exponent of self
         self_adj = self.adjusted()
@@ -2087,7 +2101,7 @@
         # self ** -infinity is infinity if self < 1, 0 if self > 1
         if other._isinfinity():
             if (other._sign == 0) == (self_adj < 0):
-                return Decimal((result_sign, (0,), 0))
+                return _dec_from_triple(result_sign, '0', 0)
             else:
                 return Infsign[result_sign]
 
@@ -2105,19 +2119,19 @@
             # self > 1 and other +ve, or self < 1 and other -ve
             # possibility of overflow
             if bound >= len(str(context.Emax)):
-                ans = Decimal((result_sign, (1,), context.Emax+1))
+                ans = _dec_from_triple(result_sign, '1', context.Emax+1)
         else:
             # self > 1 and other -ve, or self < 1 and other +ve
             # possibility of underflow to 0
             Etiny = context.Etiny()
             if bound >= len(str(-Etiny)):
-                ans = Decimal((result_sign, (1,), Etiny-1))
+                ans = _dec_from_triple(result_sign, '1', Etiny-1)
 
         # try for an exact result with precision +1
         if ans is None:
             ans = self._power_exact(other, context.prec + 1)
             if ans is not None and result_sign == 1:
-                ans = Decimal((1, ans._int, ans._exp))
+                ans = _dec_from_triple(1, ans._int, ans._exp)
 
         # usual case: inexact result, x**y computed directly as exp(y*log(x))
         if ans is None:
@@ -2138,7 +2152,7 @@
                     break
                 extra += 3
 
-            ans = Decimal((result_sign, map(int, str(coeff)), exp))
+            ans = _dec_from_triple(result_sign, str(coeff), exp)
 
         # the specification says that for non-integer other we need to
         # raise Inexact, even when the result is actually exact.  In
@@ -2150,7 +2164,8 @@
             # pad with zeros up to length context.prec+1 if necessary
             if len(ans._int) <= context.prec:
                 expdiff = context.prec+1 - len(ans._int)
-                ans = Decimal((ans._sign, ans._int+(0,)*expdiff, ans._exp-expdiff))
+                ans = _dec_from_triple(ans._sign, ans._int+'0'*expdiff,
+                                       ans._exp-expdiff)
             if ans.adjusted() < context.Emin:
                 context._raise_error(Underflow)
 
@@ -2182,14 +2197,14 @@
             return dup
 
         if not dup:
-            return Decimal( (dup._sign, (0,), 0) )
+            return _dec_from_triple(dup._sign, '0', 0)
         exp_max = [context.Emax, context.Etop()][context._clamp]
         end = len(dup._int)
         exp = dup._exp
-        while dup._int[end-1] == 0 and exp < exp_max:
+        while dup._int[end-1] == '0' and exp < exp_max:
             exp += 1
             end -= 1
-        return Decimal( (dup._sign, dup._int[:end], exp) )
+        return _dec_from_triple(dup._sign, dup._int[:end], exp)
 
     def quantize(self, exp, rounding=None, context=None, watchexp=True):
         """Quantize self so its exponent is the same as that of exp.
@@ -2230,7 +2245,7 @@
                    'target exponent out of bounds in quantize')
 
         if not self:
-            ans = Decimal((self._sign, (0,), exp._exp))
+            ans = _dec_from_triple(self._sign, '0', exp._exp)
             return ans._fix(context)
 
         self_adjusted = self.adjusted()
@@ -2290,17 +2305,18 @@
         if self._is_special:
             return Decimal(self)
         if not self:
-            return Decimal((self._sign, (0,), exp))
+            return _dec_from_triple(self._sign, '0', exp)
 
         if self._exp >= exp:
             # pad answer with zeros if necessary
-            return Decimal((self._sign, self._int + (0,)*(self._exp - exp), exp))
+            return _dec_from_triple(self._sign,
+                                        self._int + '0'*(self._exp - exp), exp)
 
         # too many digits; round and lose data.  If self.adjusted() <
         # exp-1, replace self by 10**(exp-1) before rounding
         digits = len(self._int) + self._exp - exp
         if digits < 0:
-            self = Decimal((self._sign, (1,), exp-1))
+            self = _dec_from_triple(self._sign, '1', exp-1)
             digits = 0
         this_function = getattr(self, self._pick_rounding_function[rounding])
         return this_function(digits)
@@ -2323,7 +2339,7 @@
         if self._exp >= 0:
             return Decimal(self)
         if not self:
-            return Decimal((self._sign, (0,), 0))
+            return _dec_from_triple(self._sign, '0', 0)
         if context is None:
             context = getcontext()
         if rounding is None:
@@ -2365,7 +2381,7 @@
 
         if not self:
             # exponent = self._exp // 2.  sqrt(-0) = -0
-            ans = Decimal((self._sign, (0,), self._exp // 2))
+            ans = _dec_from_triple(self._sign, '0', self._exp // 2)
             return ans._fix(context)
 
         if context is None:
@@ -2442,7 +2458,7 @@
             if n % 5 == 0:
                 n += 1
 
-        ans = Decimal((0, map(int, str(n)), e))
+        ans = _dec_from_triple(0, str(n), e)
 
         # round, and fit to current context
         context = context._shallow_copy()
@@ -2539,13 +2555,13 @@
         if self._exp >= 0:
             return True
         rest = self._int[self._exp:]
-        return rest == (0,)*len(rest)
+        return rest == '0'*len(rest)
 
     def _iseven(self):
         """Returns True if self is even.  Assumes self is an integer."""
         if not self or self._exp > 0:
             return True
-        return self._int[-1+self._exp] & 1 == 0
+        return self._int[-1+self._exp] in '02468'
 
     def adjusted(self):
         """Return the adjusted exponent of self"""
@@ -2667,18 +2683,19 @@
 
     def copy_abs(self):
         """Returns a copy with the sign set to 0. """
-        return Decimal((0, self._int, self._exp))
+        return _dec_from_triple(0, self._int, self._exp, self._is_special)
 
     def copy_negate(self):
         """Returns a copy with the sign inverted."""
         if self._sign:
-            return Decimal((0, self._int, self._exp))
+            return _dec_from_triple(0, self._int, self._exp, self._is_special)
         else:
-            return Decimal((1, self._int, self._exp))
+            return _dec_from_triple(1, self._int, self._exp, self._is_special)
 
     def copy_sign(self, other):
         """Returns self with the sign of other."""
-        return Decimal((other._sign, self._int, self._exp))
+        return _dec_from_triple(other._sign, self._int,
+                                self._exp, self._is_special)
 
     def exp(self, context=None):
         """Returns e ** self."""
@@ -2717,16 +2734,16 @@
         # larger exponent the result either overflows or underflows.
         if self._sign == 0 and adj > len(str((context.Emax+1)*3)):
             # overflow
-            ans = Decimal((0, (1,), context.Emax+1))
+            ans = _dec_from_triple(0, '1', context.Emax+1)
         elif self._sign == 1 and adj > len(str((-context.Etiny()+1)*3)):
             # underflow to 0
-            ans = Decimal((0, (1,), context.Etiny()-1))
+            ans = _dec_from_triple(0, '1', context.Etiny()-1)
         elif self._sign == 0 and adj < -p:
             # p+1 digits; final round will raise correct flags
-            ans = Decimal((0, (1,) + (0,)*(p-1) + (1,), -p))
+            ans = _dec_from_triple(0, '1' + '0'*(p-1) + '1', -p)
         elif self._sign == 1 and adj < -p-1:
             # p+1 digits; final round will raise correct flags
-            ans = Decimal((0, (9,)*(p+1), -p-1))
+            ans = _dec_from_triple(0, '9'*(p+1), -p-1)
         # general case
         else:
             op = _WorkRep(self)
@@ -2744,7 +2761,7 @@
                     break
                 extra += 3
 
-            ans = Decimal((0, map(int, str(coeff)), exp))
+            ans = _dec_from_triple(0, str(coeff), exp)
 
         # at this stage, ans should round correctly with *any*
         # rounding mode, not just with ROUND_HALF_EVEN
@@ -2809,7 +2826,7 @@
 
     def is_zero(self):
         """Return True if self is a zero; otherwise return False."""
-        return not self._is_special and self._int[0] == 0
+        return not self._is_special and self._int == '0'
 
     def _ln_exp_bound(self):
         """Compute a lower bound for the adjusted exponent of self.ln().
@@ -2878,7 +2895,7 @@
             if coeff % (5*10**(len(str(abs(coeff)))-p-1)):
                 break
             places += 3
-        ans = Decimal((int(coeff<0), map(int, str(abs(coeff))), -places))
+        ans = _dec_from_triple(int(coeff<0), str(abs(coeff)), -places)
 
         context = context._shallow_copy()
         rounding = context._set_rounding(ROUND_HALF_EVEN)
@@ -2941,7 +2958,7 @@
                                         'log10 of a negative value')
 
         # log10(10**n) = n
-        if self._int[0] == 1 and self._int[1:] == (0,)*(len(self._int) - 1):
+        if self._int[0] == '1' and self._int[1:] == '0'*(len(self._int) - 1):
             # answer may need rounding
             ans = Decimal(self._exp + len(self._int) - 1)
         else:
@@ -2959,7 +2976,7 @@
                 if coeff % (5*10**(len(str(abs(coeff)))-p-1)):
                     break
                 places += 3
-            ans = Decimal((int(coeff<0), map(int, str(abs(coeff))), -places))
+            ans = _dec_from_triple(int(coeff<0), str(abs(coeff)), -places)
 
         context = context._shallow_copy()
         rounding = context._set_rounding(ROUND_HALF_EVEN)
@@ -3006,19 +3023,19 @@
         if self._sign != 0 or self._exp != 0:
             return False
         for dig in self._int:
-            if dig not in (0, 1):
+            if dig not in '01':
                 return False
         return True
 
     def _fill_logical(self, context, opa, opb):
         dif = context.prec - len(opa)
         if dif > 0:
-            opa = (0,)*dif + opa
+            opa = '0'*dif + opa
         elif dif < 0:
             opa = opa[-context.prec:]
         dif = context.prec - len(opb)
         if dif > 0:
-            opb = (0,)*dif + opb
+            opb = '0'*dif + opb
         elif dif < 0:
             opb = opb[-context.prec:]
         return opa, opb
@@ -3034,22 +3051,15 @@
         (opa, opb) = self._fill_logical(context, self._int, other._int)
 
         # make the operation, and clean starting zeroes
-        result = [a&b for a,b in zip(opa,opb)]
-        for i,d in enumerate(result):
-            if d == 1:
-                break
-        result = tuple(result[i:])
-
-        # if empty, we must have at least a zero
-        if not result:
-            result = (0,)
-        return Decimal((0, result, 0))
+        result = "".join([str(int(a)&int(b)) for a,b in zip(opa,opb)])
+        return _dec_from_triple(0, result.lstrip('0') or '0', 0)
 
     def logical_invert(self, context=None):
         """Invert all its digits."""
         if context is None:
             context = getcontext()
-        return self.logical_xor(Decimal((0,(1,)*context.prec,0)), context)
+        return self.logical_xor(_dec_from_triple(0,'1'*context.prec,0),
+                                context)
 
     def logical_or(self, other, context=None):
         """Applies an 'or' operation between self and other's digits."""
@@ -3062,16 +3072,8 @@
         (opa, opb) = self._fill_logical(context, self._int, other._int)
 
         # make the operation, and clean starting zeroes
-        result = [a|b for a,b in zip(opa,opb)]
-        for i,d in enumerate(result):
-            if d == 1:
-                break
-        result = tuple(result[i:])
-
-        # if empty, we must have at least a zero
-        if not result:
-            result = (0,)
-        return Decimal((0, result, 0))
+        result = "".join(str(int(a)|int(b)) for a,b in zip(opa,opb))
+        return _dec_from_triple(0, result.lstrip('0') or '0', 0)
 
     def logical_xor(self, other, context=None):
         """Applies an 'xor' operation between self and other's digits."""
@@ -3084,16 +3086,8 @@
         (opa, opb) = self._fill_logical(context, self._int, other._int)
 
         # make the operation, and clean starting zeroes
-        result = [a^b for a,b in zip(opa,opb)]
-        for i,d in enumerate(result):
-            if d == 1:
-                break
-        result = tuple(result[i:])
-
-        # if empty, we must have at least a zero
-        if not result:
-            result = (0,)
-        return Decimal((0, result, 0))
+        result = "".join(str(int(a)^int(b)) for a,b in zip(opa,opb))
+        return _dec_from_triple(0, result.lstrip('0') or '0', 0)
 
     def max_mag(self, other, context=None):
         """Compares the values numerically with their sign ignored."""
@@ -3171,7 +3165,7 @@
         if self._isinfinity() == -1:
             return negInf
         if self._isinfinity() == 1:
-            return Decimal((0, (9,)*context.prec, context.Etop()))
+            return _dec_from_triple(0, '9'*context.prec, context.Etop())
 
         context = context.copy()
         context._set_rounding(ROUND_FLOOR)
@@ -3179,7 +3173,8 @@
         new_self = self._fix(context)
         if new_self != self:
             return new_self
-        return self.__sub__(Decimal((0, (1,), context.Etiny()-1)), context)
+        return self.__sub__(_dec_from_triple(0, '1', context.Etiny()-1),
+                            context)
 
     def next_plus(self, context=None):
         """Returns the smallest representable number larger than itself."""
@@ -3193,7 +3188,7 @@
         if self._isinfinity() == 1:
             return Inf
         if self._isinfinity() == -1:
-            return Decimal((1, (9,)*context.prec, context.Etop()))
+            return _dec_from_triple(1, '9'*context.prec, context.Etop())
 
         context = context.copy()
         context._set_rounding(ROUND_CEILING)
@@ -3201,7 +3196,8 @@
         new_self = self._fix(context)
         if new_self != self:
             return new_self
-        return self.__add__(Decimal((0, (1,), context.Etiny()-1)), context)
+        return self.__add__(_dec_from_triple(0, '1', context.Etiny()-1),
+                            context)
 
     def next_toward(self, other, context=None):
         """Returns the number closest to self, in the direction towards other.
@@ -3223,7 +3219,7 @@
 
         comparison = self.__cmp__(other)
         if comparison == 0:
-            return Decimal((other._sign, self._int, self._exp))
+            return self.copy_sign(other)
 
         if comparison == -1:
             ans = self.next_plus(context)
@@ -3317,19 +3313,12 @@
         rotdig = self._int
         topad = context.prec - len(rotdig)
         if topad:
-            rotdig = ((0,)*topad) + rotdig
+            rotdig = '0'*topad + rotdig
 
         # let's rotate!
         rotated = rotdig[torot:] + rotdig[:torot]
-
-        # clean starting zeroes
-        for i,d in enumerate(rotated):
-            if d != 0:
-                break
-        rotated = rotated[i:]
-
-        return Decimal((self._sign, rotated, self._exp))
-
+        return _dec_from_triple(self._sign,
+                                rotated.lstrip('0') or '0', self._exp)
 
     def scaleb (self, other, context=None):
         """Returns self operand after adding the second value to its exp."""
@@ -3350,7 +3339,7 @@
         if self._isinfinity():
             return Decimal(self)
 
-        d = Decimal((self._sign, self._int, self._exp + int(other)))
+        d = _dec_from_triple(self._sign, self._int, self._exp + int(other))
         d = d._fix(context)
         return d
 
@@ -3378,26 +3367,17 @@
         rotdig = self._int
         topad = context.prec - len(rotdig)
         if topad:
-            rotdig = ((0,)*topad) + rotdig
+            rotdig = '0'*topad + rotdig
 
         # let's shift!
         if torot < 0:
             rotated = rotdig[:torot]
         else:
-            rotated = (rotdig + ((0,) * torot))
+            rotated = rotdig + '0'*torot
             rotated = rotated[-context.prec:]
 
-        # clean starting zeroes
-        if rotated:
-            for i,d in enumerate(rotated):
-                if d != 0:
-                    break
-            rotated = rotated[i:]
-        else:
-            rotated = (0,)
-
-        return Decimal((self._sign, rotated, self._exp))
-
+        return _dec_from_triple(self._sign,
+                                    rotated.lstrip('0') or '0', self._exp)
 
     # Support for pickling, copy, and deepcopy
     def __reduce__(self):
@@ -3413,6 +3393,22 @@
             return self     # My components are also immutable
         return self.__class__(str(self))
 
+def _dec_from_triple(sign, coefficient, exponent, special=False):
+    """Create a decimal instance directly, without any validation,
+    normalization (e.g. removal of leading zeros) or argument
+    conversion.
+
+    This function is for *internal use only*.
+    """
+
+    self = object.__new__(Decimal)
+    self._sign = sign
+    self._int = coefficient
+    self._exp = exponent
+    self._is_special = special
+
+    return self
+
 ##### Context class #######################################################
 
 
@@ -4763,10 +4759,7 @@
             self.exp = None
         elif isinstance(value, Decimal):
             self.sign = value._sign
-            cum = 0
-            for digit  in value._int:
-                cum = cum * 10 + digit
-            self.int = cum
+            self.int = int(value._int)
             self.exp = value._exp
         else:
             # assert isinstance(value, tuple)
@@ -5163,53 +5156,6 @@
         raise TypeError("Unable to convert %s to Decimal" % other)
     return NotImplemented
 
-_infinity_map = {
-    'inf' : 1,
-    'infinity' : 1,
-    '+inf' : 1,
-    '+infinity' : 1,
-    '-inf' : -1,
-    '-infinity' : -1
-}
-
-def _isinfinity(num):
-    """Determines whether a string or float is infinity.
-
-    +1 for negative infinity; 0 for finite ; +1 for positive infinity
-    """
-    num = str(num).lower()
-    return _infinity_map.get(num, 0)
-
-def _isnan(num):
-    """Determines whether a string or float is NaN
-
-    (1, sign, diagnostic info as string) => NaN
-    (2, sign, diagnostic info as string) => sNaN
-    0 => not a NaN
-    """
-    num = str(num).lower()
-    if not num:
-        return 0
-
-    # Get the sign, get rid of trailing [+-]
-    sign = 0
-    if num[0] == '+':
-        num = num[1:]
-    elif num[0] == '-':  # elif avoids '+-nan'
-        num = num[1:]
-        sign = 1
-
-    if num.startswith('nan'):
-        if len(num) > 3 and not num[3:].isdigit():  # diagnostic info
-            return 0
-        return (1, sign, num[3:].lstrip('0'))
-    if num.startswith('snan'):
-        if len(num) > 4 and not num[4:].isdigit():
-            return 0
-        return (2, sign, num[4:].lstrip('0'))
-    return 0
-
-
 ##### Setup Specific Contexts ############################################
 
 # The default context prototype used by Context()
@@ -5243,6 +5189,47 @@
 )
 
 
+##### crud for parsing strings #############################################
+import re
+
+# Regular expression used for parsing numeric strings.  Additional
+# comments:
+#
+# 1. Uncomment the two '\s*' lines to allow leading and/or trailing
+# whitespace.  But note that the specification disallows whitespace in
+# a numeric string.
+#
+# 2. For finite numbers (not infinities and NaNs) the body of the
+# number between the optional sign and the optional exponent must have
+# at least one decimal digit, possibly after the decimal point.  The
+# lookahead expression '(?=\d|\.\d)' checks this.
+#
+# As the flag UNICODE is not enabled here, we're explicitly avoiding any
+# other meaning for \d than the numbers [0-9].
+
+import re
+_parser = re.compile(r"""     # A numeric string consists of:
+#    \s*
+    (?P<sign>[-+])?           # an optional sign, followed by either...
+    (
+        (?=\d|\.\d)           # ...a number (with at least one digit)
+        (?P<int>\d*)          # consisting of a (possibly empty) integer part
+        (\.(?P<frac>\d*))?    # followed by an optional fractional part
+        (E(?P<exp>[-+]?\d+))? # followed by an optional exponent, or...
+    |
+        Inf(inity)?           # ...an infinity, or...
+    |
+        (?P<signal>s)?        # ...an (optionally signaling)
+        NaN                   # NaN
+        (?P<diag>\d*)         # with (possibly empty) diagnostic information.
+    )
+#    \s*
+    $
+""", re.VERBOSE | re.IGNORECASE).match
+
+del re
+
+
 ##### Useful Constants (internal use only) ################################
 
 # Reusable defaults
@@ -5259,76 +5246,6 @@
 Infsign = (Inf, negInf)
 
 
-##### crud for parsing strings #############################################
-import re
-
-# There's an optional sign at the start, and an optional exponent
-# at the end.  The exponent has an optional sign and at least one
-# digit.  In between, must have either at least one digit followed
-# by an optional fraction, or a decimal point followed by at least
-# one digit.  Yuck.
-
-_parser = re.compile(r"""
-#    \s*
-    (?P<sign>[-+])?
-    (
-        (?P<int>\d+) (\. (?P<frac>\d*))?
-    |
-        \. (?P<onlyfrac>\d+)
-    )
-    ([eE](?P<exp>[-+]? \d+))?
-#    \s*
-    $
-""", re.VERBOSE).match  # Uncomment the \s* to allow leading or trailing spaces.
-
-del re
-
-def _string2exact(s):
-    """Return sign, n, p s.t.
-
-    Float string value == -1**sign * n * 10**p exactly
-    """
-    m = _parser(s)
-    if m is None:
-        raise ValueError("invalid literal for Decimal: %r" % s)
-
-    if m.group('sign') == "-":
-        sign = 1
-    else:
-        sign = 0
-
-    exp = m.group('exp')
-    if exp is None:
-        exp = 0
-    else:
-        exp = int(exp)
-
-    intpart = m.group('int')
-    if intpart is None:
-        intpart = ""
-        fracpart = m.group('onlyfrac')
-    else:
-        fracpart = m.group('frac')
-        if fracpart is None:
-            fracpart = ""
-
-    exp -= len(fracpart)
-
-    mantissa = intpart + fracpart
-    tmp = map(int, mantissa)
-    backup = tmp
-    while tmp and tmp[0] == 0:
-        del tmp[0]
-
-    # It's a zero
-    if not tmp:
-        if backup:
-            return (sign, tuple(backup), exp)
-        return (sign, (0,), exp)
-    mantissa = tuple(tmp)
-
-    return (sign, mantissa, exp)
-
 
 if __name__ == '__main__':
     import doctest, sys
diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py
index 27d1aa6..dbe7023 100644
--- a/Lib/test/test_decimal.py
+++ b/Lib/test/test_decimal.py
@@ -464,6 +464,7 @@
         self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, None, 1), 2) )
         self.assertRaises(ValueError, Decimal, (1, (4, -3, 4, 9, 1), 2) )
         self.assertRaises(ValueError, Decimal, (1, (4, 10, 4, 9, 1), 2) )
+        self.assertRaises(ValueError, Decimal, (1, (4, 3, 4, 'a', 1), 2) )
 
     def test_explicit_from_Decimal(self):