Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
cce8df2f
Commit
cce8df2f
authored
Sep 18, 2007
by
Facundo Batista
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Speed up of the various division operations (remainder, divide,
divideint and divmod). Thanks Mark Dickinson.
parent
745e48df
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
139 additions
and
161 deletions
+139
-161
Lib/decimal.py
Lib/decimal.py
+139
-161
No files found.
Lib/decimal.py
View file @
cce8df2f
...
@@ -244,9 +244,7 @@ class DivisionByZero(DecimalException, ZeroDivisionError):
...
@@ -244,9 +244,7 @@ class DivisionByZero(DecimalException, ZeroDivisionError):
-0, for power.
-0, for power.
"""
"""
def
handle
(
self
,
context
,
sign
,
double
=
None
,
*
args
):
def
handle
(
self
,
context
,
sign
,
*
args
):
if
double
is
not
None
:
return
(
Infsign
[
sign
],)
*
2
return
Infsign
[
sign
]
return
Infsign
[
sign
]
class
DivisionImpossible
(
InvalidOperation
):
class
DivisionImpossible
(
InvalidOperation
):
...
@@ -258,7 +256,7 @@ class DivisionImpossible(InvalidOperation):
...
@@ -258,7 +256,7 @@ class DivisionImpossible(InvalidOperation):
"""
"""
def
handle
(
self
,
context
,
*
args
):
def
handle
(
self
,
context
,
*
args
):
return
(
NaN
,
NaN
)
return
NaN
class
DivisionUndefined
(
InvalidOperation
,
ZeroDivisionError
):
class
DivisionUndefined
(
InvalidOperation
,
ZeroDivisionError
):
"""Undefined result of division.
"""Undefined result of division.
...
@@ -268,9 +266,7 @@ class DivisionUndefined(InvalidOperation, ZeroDivisionError):
...
@@ -268,9 +266,7 @@ class DivisionUndefined(InvalidOperation, ZeroDivisionError):
the dividend is also zero. The result is [0,qNaN].
the dividend is also zero. The result is [0,qNaN].
"""
"""
def
handle
(
self
,
context
,
tup
=
None
,
*
args
):
def
handle
(
self
,
context
,
*
args
):
if
tup
is
not
None
:
return
(
NaN
,
NaN
)
# for 0 %0, 0 // 0
return
NaN
return
NaN
class
Inexact
(
DecimalException
):
class
Inexact
(
DecimalException
):
...
@@ -1151,157 +1147,97 @@ class Decimal(object):
...
@@ -1151,157 +1147,97 @@ class Decimal(object):
def
__div__
(
self
,
other
,
context
=
None
):
def
__div__
(
self
,
other
,
context
=
None
):
"""Return self / other."""
"""Return self / other."""
return
self
.
_divide
(
other
,
context
=
context
)
__truediv__
=
__div__
def
_divide
(
self
,
other
,
divmod
=
0
,
context
=
None
):
"""Return a / b, to context.prec precision.
divmod:
0 => true division
1 => (a //b, a%b)
2 => a //b
3 => a%b
Actually, if divmod is 2 or 3 a tuple is returned, but errors for
computing the other value are not raised.
"""
other
=
_convert_other
(
other
)
other
=
_convert_other
(
other
)
if
other
is
NotImplemented
:
if
other
is
NotImplemented
:
if
divmod
in
(
0
,
1
):
return
NotImplemented
return
NotImplemented
return
(
NotImplemented
,
NotImplemented
)
if
context
is
None
:
if
context
is
None
:
context
=
getcontext
()
context
=
getcontext
()
shouldround
=
context
.
_rounding_decision
==
ALWAYS_ROUND
sign
=
self
.
_sign
^
other
.
_sign
sign
=
self
.
_sign
^
other
.
_sign
if
self
.
_is_special
or
other
.
_is_special
:
if
self
.
_is_special
or
other
.
_is_special
:
ans
=
self
.
_check_nans
(
other
,
context
)
ans
=
self
.
_check_nans
(
other
,
context
)
if
ans
:
if
ans
:
if
divmod
:
return
(
ans
,
ans
)
return
ans
return
ans
if
self
.
_isinfinity
()
and
other
.
_isinfinity
():
if
self
.
_isinfinity
()
and
other
.
_isinfinity
():
if
divmod
:
reloco
=
(
context
.
_raise_error
(
InvalidOperation
,
'(+-)INF // (+-)INF'
),
context
.
_raise_error
(
InvalidOperation
,
'(+-)INF % (+-)INF'
))
return
reloco
return
context
.
_raise_error
(
InvalidOperation
,
'(+-)INF/(+-)INF'
)
return
context
.
_raise_error
(
InvalidOperation
,
'(+-)INF/(+-)INF'
)
if
self
.
_isinfinity
():
if
self
.
_isinfinity
():
if
divmod
==
1
:
return
(
Infsign
[
sign
],
context
.
_raise_error
(
InvalidOperation
,
'INF % x'
))
elif
divmod
==
2
:
return
(
Infsign
[
sign
],
NaN
)
elif
divmod
==
3
:
return
(
Infsign
[
sign
],
context
.
_raise_error
(
InvalidOperation
,
'INF % x'
))
return
Infsign
[
sign
]
return
Infsign
[
sign
]
if
other
.
_isinfinity
():
if
other
.
_isinfinity
():
if
divmod
:
otherside
=
Decimal
(
self
)
if
shouldround
and
(
divmod
==
1
or
divmod
==
3
):
otherside
=
otherside
.
_fix
(
context
)
return
(
Decimal
((
sign
,
(
0
,),
0
)),
otherside
)
context
.
_raise_error
(
Clamped
,
'Division by infinity'
)
context
.
_raise_error
(
Clamped
,
'Division by infinity'
)
return
Decimal
((
sign
,
(
0
,),
context
.
Etiny
()))
return
Decimal
((
sign
,
(
0
,),
context
.
Etiny
()))
# Special cases for zeroes
# Special cases for zeroes
if
not
self
and
not
other
:
if
divmod
:
return
context
.
_raise_error
(
DivisionUndefined
,
'0 / 0'
,
1
)
return
context
.
_raise_error
(
DivisionUndefined
,
'0 / 0'
)
if
not
self
:
if
divmod
:
otherside
=
Decimal
((
self
.
_sign
,
(
0
,),
min
(
self
.
_exp
,
other
.
_exp
)))
if
shouldround
and
(
divmod
==
1
or
divmod
==
3
):
otherside
=
otherside
.
_fix
(
context
)
return
(
Decimal
((
sign
,
(
0
,),
0
)),
otherside
)
exp
=
self
.
_exp
-
other
.
_exp
ans
=
Decimal
((
sign
,
(
0
,),
exp
))
ans
=
ans
.
_fix
(
context
)
return
ans
if
not
other
:
if
not
other
:
if
divmod
:
if
not
self
:
return
context
.
_raise_error
(
DivisionByZero
,
'divmod(x,0)'
,
return
context
.
_raise_error
(
DivisionUndefined
,
'0 / 0'
)
sign
,
1
)
return
context
.
_raise_error
(
DivisionByZero
,
'x / 0'
,
sign
)
return
context
.
_raise_error
(
DivisionByZero
,
'x / 0'
,
sign
)
# OK, so neither = 0, INF or NaN
if
not
self
:
exp
=
self
.
_exp
-
other
.
_exp
# If we're dividing into ints, and self < other, stop.
coeff
=
0
# self.__abs__(0) does not round.
else
:
if
divmod
and
(
self
.
__abs__
(
0
,
context
)
<
other
.
__abs__
(
0
,
context
)):
# OK, so neither = 0, INF or NaN
shift
=
len
(
other
.
_int
)
-
len
(
self
.
_int
)
+
context
.
prec
+
1
exp
=
self
.
_exp
-
other
.
_exp
-
shift
op1
=
_WorkRep
(
self
)
op2
=
_WorkRep
(
other
)
if
shift
>=
0
:
coeff
,
remainder
=
divmod
(
op1
.
int
*
10
**
shift
,
op2
.
int
)
else
:
coeff
,
remainder
=
divmod
(
op1
.
int
,
op2
.
int
*
10
**-
shift
)
if
remainder
:
# result is not exact; adjust to ensure correct rounding
if
coeff
%
5
==
0
:
coeff
+=
1
else
:
# result is exact; get as close to ideal exponent as possible
ideal_exp
=
self
.
_exp
-
other
.
_exp
while
exp
<
ideal_exp
and
coeff
%
10
==
0
:
coeff
//=
10
exp
+=
1
if
divmod
==
1
or
divmod
==
3
:
ans
=
Decimal
((
sign
,
map
(
int
,
str
(
coeff
)),
exp
))
exp
=
min
(
self
.
_exp
,
other
.
_exp
)
return
ans
.
_fix
(
context
)
ans2
=
self
.
_rescale
(
exp
,
context
.
rounding
)
if
shouldround
:
ans2
=
ans2
.
_fix
(
context
)
return
(
Decimal
(
(
sign
,
(
0
,),
0
)
),
ans2
)
elif
divmod
==
2
:
__truediv__
=
__div__
# Don't round the mod part, if we don't need it.
return
(
Decimal
(
(
sign
,
(
0
,),
0
)
),
Decimal
(
self
))
op1
=
_WorkRep
(
self
)
def
_divide
(
self
,
other
,
context
):
op2
=
_WorkRep
(
other
)
"""Return (self // other, self % other), to context.prec precision.
op1
,
op2
,
adjust
=
_adjust_coefficients
(
op1
,
op2
)
res
=
_WorkRep
(
(
sign
,
0
,
(
op1
.
exp
-
op2
.
exp
))
)
if
divmod
and
res
.
exp
>
context
.
prec
+
1
:
return
context
.
_raise_error
(
DivisionImpossible
)
prec_limit
=
10
**
context
.
prec
Assumes that neither self nor other is a NaN, that self is not
while
1
:
infinite and that other is nonzero.
while
op2
.
int
<=
op1
.
int
:
"""
res
.
int
+=
1
sign
=
self
.
_sign
^
other
.
_sign
op1
.
int
-=
op2
.
int
if
other
.
_isinfinity
():
if
res
.
exp
==
0
and
divmod
:
ideal_exp
=
self
.
_exp
if
res
.
int
>=
prec_limit
and
shouldround
:
else
:
return
context
.
_raise_error
(
DivisionImpossible
)
ideal_exp
=
min
(
self
.
_exp
,
other
.
_exp
)
otherside
=
Decimal
(
op1
)
exp
=
min
(
self
.
_exp
,
other
.
_exp
)
otherside
=
otherside
.
_rescale
(
exp
,
context
.
rounding
)
if
shouldround
and
(
divmod
==
1
or
divmod
==
3
):
otherside
=
otherside
.
_fix
(
context
)
return
(
Decimal
(
res
),
otherside
)
if
op1
.
int
==
0
and
adjust
>=
0
and
not
divmod
:
break
if
res
.
int
>=
prec_limit
and
shouldround
:
if
divmod
:
return
context
.
_raise_error
(
DivisionImpossible
)
shouldround
=
1
# Really, the answer is a bit higher, so adding a one to
# the end will make sure the rounding is right.
if
op1
.
int
!=
0
:
res
.
int
*=
10
res
.
int
+=
1
res
.
exp
-=
1
break
expdiff
=
self
.
adjusted
()
-
other
.
adjusted
()
res
.
int
*=
10
if
not
self
or
other
.
_isinfinity
()
or
expdiff
<=
-
2
:
res
.
exp
-=
1
return
(
Decimal
((
sign
,
(
0
,),
0
)),
adjust
+=
1
self
.
_rescale
(
ideal_exp
,
context
.
rounding
))
op1
.
int
*=
10
if
expdiff
<=
context
.
prec
:
op1
.
exp
-=
1
op1
=
_WorkRep
(
self
)
op2
=
_WorkRep
(
other
)
if
op1
.
exp
>=
op2
.
exp
:
op1
.
int
*=
10
**
(
op1
.
exp
-
op2
.
exp
)
else
:
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
)))
ans
=
Decimal
(
res
)
# Here the quotient is too large to be representable
if
shouldround
:
ans
=
context
.
_raise_error
(
DivisionImpossible
,
ans
=
ans
.
_fix
(
context
)
'quotient too large in //, % or divmod'
)
return
ans
return
ans
,
ans
def
__rdiv__
(
self
,
other
,
context
=
None
):
def
__rdiv__
(
self
,
other
,
context
=
None
):
"""Swaps self/other and returns __div__."""
"""Swaps self/other and returns __div__."""
...
@@ -1313,9 +1249,40 @@ class Decimal(object):
...
@@ -1313,9 +1249,40 @@ class Decimal(object):
def
__divmod__
(
self
,
other
,
context
=
None
):
def
__divmod__
(
self
,
other
,
context
=
None
):
"""
"""
(self // other, self % other)
Return
(self // other, self % other)
"""
"""
return
self
.
_divide
(
other
,
1
,
context
)
other
=
_convert_other
(
other
)
if
other
is
NotImplemented
:
return
other
if
context
is
None
:
context
=
getcontext
()
ans
=
self
.
_check_nans
(
other
,
context
)
if
ans
:
return
(
ans
,
ans
)
sign
=
self
.
_sign
^
other
.
_sign
if
self
.
_isinfinity
():
if
other
.
_isinfinity
():
ans
=
context
.
_raise_error
(
InvalidOperation
,
'divmod(INF, INF)'
)
return
ans
,
ans
else
:
return
(
Infsign
[
sign
],
context
.
_raise_error
(
InvalidOperation
,
'INF % x'
))
if
not
other
:
if
not
self
:
ans
=
context
.
_raise_error
(
DivisionUndefined
,
'divmod(0, 0)'
)
return
ans
,
ans
else
:
return
(
context
.
_raise_error
(
DivisionByZero
,
'x // 0'
,
sign
),
context
.
_raise_error
(
InvalidOperation
,
'x % 0'
))
quotient
,
remainder
=
self
.
_divide
(
other
,
context
)
if
context
.
_rounding_decision
==
ALWAYS_ROUND
:
remainder
=
remainder
.
_fix
(
context
)
return
quotient
,
remainder
def
__rdivmod__
(
self
,
other
,
context
=
None
):
def
__rdivmod__
(
self
,
other
,
context
=
None
):
"""Swaps self/other and returns __divmod__."""
"""Swaps self/other and returns __divmod__."""
...
@@ -1332,15 +1299,25 @@ class Decimal(object):
...
@@ -1332,15 +1299,25 @@ class Decimal(object):
if
other
is
NotImplemented
:
if
other
is
NotImplemented
:
return
other
return
other
if
self
.
_is_special
or
other
.
_is_special
:
if
context
is
None
:
ans
=
self
.
_check_nans
(
other
,
context
)
context
=
getcontext
()
if
ans
:
return
ans
if
self
and
not
other
:
ans
=
self
.
_check_nans
(
other
,
context
)
return
context
.
_raise_error
(
InvalidOperation
,
'x % 0'
)
if
ans
:
return
ans
return
self
.
_divide
(
other
,
3
,
context
)[
1
]
if
self
.
_isinfinity
():
return
context
.
_raise_error
(
InvalidOperation
,
'INF % x'
)
elif
not
other
:
if
self
:
return
context
.
_raise_error
(
InvalidOperation
,
'x % 0'
)
else
:
return
context
.
_raise_error
(
DivisionUndefined
,
'0 % 0'
)
remainder
=
self
.
_divide
(
other
,
context
)[
1
]
if
context
.
_rounding_decision
==
ALWAYS_ROUND
:
remainder
=
remainder
.
_fix
(
context
)
return
remainder
def
__rmod__
(
self
,
other
,
context
=
None
):
def
__rmod__
(
self
,
other
,
context
=
None
):
"""Swaps self/other and returns __mod__."""
"""Swaps self/other and returns __mod__."""
...
@@ -1391,7 +1368,7 @@ class Decimal(object):
...
@@ -1391,7 +1368,7 @@ class Decimal(object):
expdiff
=
self
.
adjusted
()
-
other
.
adjusted
()
expdiff
=
self
.
adjusted
()
-
other
.
adjusted
()
if
expdiff
>=
context
.
prec
+
1
:
if
expdiff
>=
context
.
prec
+
1
:
# expdiff >= prec+1 => abs(self/other) > 10**prec
# expdiff >= prec+1 => abs(self/other) > 10**prec
return
context
.
_raise_error
(
DivisionImpossible
)
[
0
]
return
context
.
_raise_error
(
DivisionImpossible
)
if
expdiff
<=
-
2
:
if
expdiff
<=
-
2
:
# expdiff <= -2 => abs(self/other) < 0.1
# expdiff <= -2 => abs(self/other) < 0.1
ans
=
self
.
_rescale
(
ideal_exponent
,
context
.
rounding
)
ans
=
self
.
_rescale
(
ideal_exponent
,
context
.
rounding
)
...
@@ -1413,7 +1390,7 @@ class Decimal(object):
...
@@ -1413,7 +1390,7 @@ class Decimal(object):
q
+=
1
q
+=
1
if
q
>=
10
**
context
.
prec
:
if
q
>=
10
**
context
.
prec
:
return
context
.
_raise_error
(
DivisionImpossible
)
[
0
]
return
context
.
_raise_error
(
DivisionImpossible
)
# result has same sign as self unless r is negative
# result has same sign as self unless r is negative
sign
=
self
.
_sign
sign
=
self
.
_sign
...
@@ -1426,7 +1403,31 @@ class Decimal(object):
...
@@ -1426,7 +1403,31 @@ class Decimal(object):
def
__floordiv__
(
self
,
other
,
context
=
None
):
def
__floordiv__
(
self
,
other
,
context
=
None
):
"""self // other"""
"""self // other"""
return
self
.
_divide
(
other
,
2
,
context
)[
0
]
other
=
_convert_other
(
other
)
if
other
is
NotImplemented
:
return
other
if
context
is
None
:
context
=
getcontext
()
ans
=
self
.
_check_nans
(
other
,
context
)
if
ans
:
return
ans
if
self
.
_isinfinity
():
if
other
.
_isinfinity
():
return
context
.
_raise_error
(
InvalidOperation
,
'INF // INF'
)
else
:
return
Infsign
[
self
.
_sign
^
other
.
_sign
]
if
not
other
:
if
self
:
return
context
.
_raise_error
(
DivisionByZero
,
'x // 0'
,
self
.
_sign
^
other
.
_sign
)
else
:
return
context
.
_raise_error
(
DivisionUndefined
,
'0 // 0'
)
return
self
.
_divide
(
other
,
context
)[
0
]
def
__rfloordiv__
(
self
,
other
,
context
=
None
):
def
__rfloordiv__
(
self
,
other
,
context
=
None
):
"""Swaps self/other and returns __floordiv__."""
"""Swaps self/other and returns __floordiv__."""
...
@@ -2979,7 +2980,7 @@ class Decimal(object):
...
@@ -2979,7 +2980,7 @@ class Decimal(object):
# logb(0) = -Inf, DivisionByZero
# logb(0) = -Inf, DivisionByZero
if
not
self
:
if
not
self
:
return
context
.
_raise_error
(
DivisionByZero
,
'logb(0)'
,
-
1
)
return
context
.
_raise_error
(
DivisionByZero
,
'logb(0)'
,
1
)
# otherwise, simply return the adjusted exponent of self, as a
# otherwise, simply return the adjusted exponent of self, as a
# Decimal. Note that no attempt is made to fit the result
# Decimal. Note that no attempt is made to fit the result
...
@@ -4793,29 +4794,6 @@ def _normalize(op1, op2, shouldround = 0, prec = 0):
...
@@ -4793,29 +4794,6 @@ def _normalize(op1, op2, shouldround = 0, prec = 0):
tmp
.
exp
=
other
.
exp
tmp
.
exp
=
other
.
exp
return
op1
,
op2
return
op1
,
op2
def
_adjust_coefficients
(
op1
,
op2
):
"""Adjust op1, op2 so that op2.int * 10 > op1.int >= op2.int.
Returns the adjusted op1, op2 as well as the change in op1.exp-op2.exp.
Used on _WorkRep instances during division.
"""
adjust
=
0
# If op1 is smaller, make it larger
while
op2
.
int
>
op1
.
int
:
op1
.
int
*=
10
op1
.
exp
-=
1
adjust
+=
1
# If op2 is too small, make it larger
while
op1
.
int
>=
(
10
*
op2
.
int
):
op2
.
int
*=
10
op2
.
exp
-=
1
adjust
-=
1
return
op1
,
op2
,
adjust
##### Integer arithmetic functions used by ln, log10, exp and __pow__ #####
##### Integer arithmetic functions used by ln, log10, exp and __pow__ #####
# This function from Tim Peters was taken from here:
# This function from Tim Peters was taken from here:
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment