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
045e6351
Commit
045e6351
authored
May 05, 2016
by
Steven D'Aprano
Browse files
Options
Browse Files
Download
Plain Diff
Automated merge with
ssh://hg.python.org/cpython
parents
fcce462e
3b06e243
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
44 additions
and
55 deletions
+44
-55
Lib/statistics.py
Lib/statistics.py
+30
-38
Lib/test/test_statistics.py
Lib/test/test_statistics.py
+14
-17
No files found.
Lib/statistics.py
View file @
045e6351
...
...
@@ -105,6 +105,7 @@ import math
from
fractions
import
Fraction
from
decimal
import
Decimal
from
itertools
import
groupby
from
bisect
import
bisect_left
,
bisect_right
...
...
@@ -223,56 +224,26 @@ def _exact_ratio(x):
# Optimise the common case of floats. We expect that the most often
# used numeric type will be builtin floats, so try to make this as
# fast as possible.
if
type
(
x
)
is
float
:
if
type
(
x
)
is
float
or
type
(
x
)
is
Decimal
:
return
x
.
as_integer_ratio
()
try
:
# x may be an int, Fraction, or Integral ABC.
return
(
x
.
numerator
,
x
.
denominator
)
except
AttributeError
:
try
:
# x may be a float subclass.
# x may be a float
or Decimal
subclass.
return
x
.
as_integer_ratio
()
except
AttributeError
:
try
:
# x may be a Decimal.
return
_decimal_to_ratio
(
x
)
except
AttributeError
:
# Just give up?
pass
# Just give up?
pass
except
(
OverflowError
,
ValueError
):
# float NAN or INF.
assert
not
math
.
isfinite
(
x
)
assert
not
_
isfinite
(
x
)
return
(
x
,
None
)
msg
=
"can't convert type '{}' to numerator/denominator"
raise
TypeError
(
msg
.
format
(
type
(
x
).
__name__
))
# FIXME This is faster than Fraction.from_decimal, but still too slow.
def
_decimal_to_ratio
(
d
):
"""Convert Decimal d to exact integer ratio (numerator, denominator).
>>> from decimal import Decimal
>>> _decimal_to_ratio(Decimal("2.6"))
(26, 10)
"""
sign
,
digits
,
exp
=
d
.
as_tuple
()
if
exp
in
(
'F'
,
'n'
,
'N'
):
# INF, NAN, sNAN
assert
not
d
.
is_finite
()
return
(
d
,
None
)
num
=
0
for
digit
in
digits
:
num
=
num
*
10
+
digit
if
exp
<
0
:
den
=
10
**-
exp
else
:
num
*=
10
**
exp
den
=
1
if
sign
:
num
=
-
num
return
(
num
,
den
)
def
_convert
(
value
,
T
):
"""Convert value to given numeric type T."""
if
type
(
value
)
is
T
:
...
...
@@ -305,6 +276,21 @@ def _counts(data):
return
table
def
_find_lteq
(
a
,
x
):
'Locate the leftmost value exactly equal to x'
i
=
bisect_left
(
a
,
x
)
if
i
!=
len
(
a
)
and
a
[
i
]
==
x
:
return
i
raise
ValueError
def
_find_rteq
(
a
,
l
,
x
):
'Locate the rightmost value exactly equal to x'
i
=
bisect_right
(
a
,
x
,
lo
=
l
)
if
i
!=
(
len
(
a
)
+
1
)
and
a
[
i
-
1
]
==
x
:
return
i
-
1
raise
ValueError
# === Measures of central tendency (averages) ===
def
mean
(
data
):
...
...
@@ -442,9 +428,15 @@ def median_grouped(data, interval=1):
except
TypeError
:
# Mixed type. For now we just coerce to float.
L
=
float
(
x
)
-
float
(
interval
)
/
2
cf
=
data
.
index
(
x
)
# Number of values below the median interval.
# FIXME The following line could be more efficient for big lists.
f
=
data
.
count
(
x
)
# Number of data points in the median interval.
# Uses bisection search to search for x in data with log(n) time complexity
# Find the position of leftmost occurence of x in data
l1
=
_find_lteq
(
data
,
x
)
# Find the position of rightmost occurence of x in data[l1...len(data)]
# Assuming always l1 <= l2
l2
=
_find_rteq
(
data
,
l1
,
x
)
cf
=
l1
f
=
l2
-
l1
+
1
return
L
+
interval
*
(
n
/
2
-
cf
)
/
f
...
...
Lib/test/test_statistics.py
View file @
045e6351
...
...
@@ -699,13 +699,12 @@ class ExactRatioTest(unittest.TestCase):
num
,
den
=
statistics
.
_exact_ratio
(
x
)
self
.
assertEqual
(
x
,
num
/
den
)
@
unittest
.
skipIf
(
True
,
"temporarily disabled: see #25928"
)
def
test_decimal
(
self
):
D
=
Decimal
_exact_ratio
=
statistics
.
_exact_ratio
self
.
assertEqual
(
_exact_ratio
(
D
(
"0.125"
)),
(
1
25
,
1000
))
self
.
assertEqual
(
_exact_ratio
(
D
(
"12.345"
)),
(
12345
,
10
00
))
self
.
assertEqual
(
_exact_ratio
(
D
(
"-1.98"
)),
(
-
198
,
10
0
))
self
.
assertEqual
(
_exact_ratio
(
D
(
"0.125"
)),
(
1
,
8
))
self
.
assertEqual
(
_exact_ratio
(
D
(
"12.345"
)),
(
2469
,
2
00
))
self
.
assertEqual
(
_exact_ratio
(
D
(
"-1.98"
)),
(
-
99
,
5
0
))
def
test_inf
(
self
):
INF
=
float
(
"INF"
)
...
...
@@ -731,7 +730,6 @@ class ExactRatioTest(unittest.TestCase):
self
.
assertIs
(
ratio
[
1
],
None
)
self
.
assertEqual
(
type
(
ratio
[
0
]),
type
(
nan
))
@
unittest
.
skipIf
(
True
,
"temporarily disabled: see #25928"
)
def
test_decimal_nan
(
self
):
NAN
=
Decimal
(
"NAN"
)
sNAN
=
Decimal
(
"sNAN"
)
...
...
@@ -745,18 +743,18 @@ class ExactRatioTest(unittest.TestCase):
class
DecimalToRatioTest
(
unittest
.
TestCase
):
# Test _
decimal_to
_ratio private function.
# Test _
exact
_ratio private function.
def
test_infinity
(
self
):
# Test that INFs are handled correctly.
inf
=
Decimal
(
'INF'
)
self
.
assertEqual
(
statistics
.
_
decimal_to
_ratio
(
inf
),
(
inf
,
None
))
self
.
assertEqual
(
statistics
.
_
decimal_to
_ratio
(
-
inf
),
(
-
inf
,
None
))
self
.
assertEqual
(
statistics
.
_
exact
_ratio
(
inf
),
(
inf
,
None
))
self
.
assertEqual
(
statistics
.
_
exact
_ratio
(
-
inf
),
(
-
inf
,
None
))
def
test_nan
(
self
):
# Test that NANs are handled correctly.
for
nan
in
(
Decimal
(
'NAN'
),
Decimal
(
'sNAN'
)):
num
,
den
=
statistics
.
_
decimal_to
_ratio
(
nan
)
num
,
den
=
statistics
.
_
exact
_ratio
(
nan
)
# Because NANs always compare non-equal, we cannot use assertEqual.
# Nor can we use an identity test, as we don't guarantee anything
# about the object identity.
...
...
@@ -769,30 +767,30 @@ class DecimalToRatioTest(unittest.TestCase):
for
d
in
numbers
:
# First test positive decimals.
assert
d
>
0
num
,
den
=
statistics
.
_
decimal_to
_ratio
(
d
)
num
,
den
=
statistics
.
_
exact
_ratio
(
d
)
self
.
assertGreaterEqual
(
num
,
0
)
self
.
assertGreater
(
den
,
0
)
# Then test negative decimals.
num
,
den
=
statistics
.
_
decimal_to
_ratio
(
-
d
)
num
,
den
=
statistics
.
_
exact
_ratio
(
-
d
)
self
.
assertLessEqual
(
num
,
0
)
self
.
assertGreater
(
den
,
0
)
def
test_negative_exponent
(
self
):
# Test result when the exponent is negative.
t
=
statistics
.
_
decimal_to
_ratio
(
Decimal
(
"0.1234"
))
self
.
assertEqual
(
t
,
(
1234
,
10
000
))
t
=
statistics
.
_
exact
_ratio
(
Decimal
(
"0.1234"
))
self
.
assertEqual
(
t
,
(
617
,
5
000
))
def
test_positive_exponent
(
self
):
# Test results when the exponent is positive.
t
=
statistics
.
_
decimal_to
_ratio
(
Decimal
(
"1.234e7"
))
t
=
statistics
.
_
exact
_ratio
(
Decimal
(
"1.234e7"
))
self
.
assertEqual
(
t
,
(
12340000
,
1
))
def
test_regression_20536
(
self
):
# Regression test for issue 20536.
# See http://bugs.python.org/issue20536
t
=
statistics
.
_
decimal_to
_ratio
(
Decimal
(
"1e2"
))
t
=
statistics
.
_
exact
_ratio
(
Decimal
(
"1e2"
))
self
.
assertEqual
(
t
,
(
100
,
1
))
t
=
statistics
.
_
decimal_to
_ratio
(
Decimal
(
"1.47e5"
))
t
=
statistics
.
_
exact
_ratio
(
Decimal
(
"1.47e5"
))
self
.
assertEqual
(
t
,
(
147000
,
1
))
...
...
@@ -1260,7 +1258,6 @@ class SumSpecialValues(NumericTestCase):
with
decimal
.
localcontext
(
decimal
.
BasicContext
):
self
.
assertRaises
(
decimal
.
InvalidOperation
,
statistics
.
_sum
,
data
)
@
unittest
.
skipIf
(
True
,
"temporarily disabled: see #25928"
)
def
test_decimal_snan_raises
(
self
):
# Adding sNAN should raise InvalidOperation.
sNAN
=
Decimal
(
'sNAN'
)
...
...
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