diff --git a/Doc/library/statistics.rst b/Doc/library/statistics.rst index 9ff30211ebcf15..167a468b3b9b26 100644 --- a/Doc/library/statistics.rst +++ b/Doc/library/statistics.rst @@ -160,7 +160,7 @@ However, for reading convenience, most of the examples show sorted sequences. .. function:: fmean(data, weights=None) - Convert *data* to floats and compute the arithmetic mean. + Compute the arithmetic mean as a :class:`float`. This runs faster than the :func:`mean` function and it always returns a :class:`float`. The *data* may be a sequence or iterable. If the input @@ -183,7 +183,10 @@ However, for reading convenience, most of the examples show sorted sequences. 87.6 If *weights* is supplied, it must be the same length as the *data* or - a :exc:`ValueError` will be raised. + a :exc:`ValueError` will be raised. The values in *data* and *weights* + must have compatible types for multiplication. For example, + :class:`~decimal.Decimal` values cannot be mixed with :class:`float` + or :class:`~fractions.Fraction` values. .. versionadded:: 3.8 diff --git a/Lib/statistics.py b/Lib/statistics.py index eee3e6eb94e990..b6235f89b2eab2 100644 --- a/Lib/statistics.py +++ b/Lib/statistics.py @@ -181,7 +181,7 @@ def mean(data): def fmean(data, weights=None): - """Convert data to floats and compute the arithmetic mean. + """Compute the arithmetic mean as a float. This runs faster than the mean() function and it always returns a float. If the input dataset is empty, it raises a StatisticsError. @@ -189,6 +189,9 @@ def fmean(data, weights=None): >>> fmean([3.5, 4.0, 5.25]) 4.25 + If provided, weights must have the same length as data. The values in + data and weights must have compatible types for multiplication. + Decimals cannot be mixed with floats or fractions. """ if weights is None: @@ -220,7 +223,7 @@ def fmean(data, weights=None): if not den: raise StatisticsError('sum of weights must be non-zero') - return num / den + return float(num) / den def geometric_mean(data): diff --git a/Lib/test/test_statistics.py b/Lib/test/test_statistics.py index 700c5ac304f717..4a57ac488728fa 100644 --- a/Lib/test/test_statistics.py +++ b/Lib/test/test_statistics.py @@ -1932,6 +1932,18 @@ def test_weights(self): with self.assertRaises(StatisticsError): fmean(iter([10, 20]), iter([-1, 1])) # sum of weights is zero + def test_decimal_weights(self): + for data, weights in [ + ([Decimal(2), Decimal(4), Decimal(8)], [1, 2, 1]), + ([2, 4, 8], [Decimal(1), Decimal(2), Decimal(1)]), + ([Decimal(2), Decimal(4), Decimal(8)], + [Decimal(1), Decimal(2), Decimal(1)]), + ]: + with self.subTest(data=data, weights=weights): + result = statistics.fmean(data, weights) + self.assertIs(type(result), float) + self.assertEqual(result, 4.5) + # === Tests for variances and standard deviations === diff --git a/Misc/NEWS.d/next/Library/2026-10-20-02-30-00.gh-issue-131723.aH8nY4.rst b/Misc/NEWS.d/next/Library/2026-10-20-02-30-00.gh-issue-131723.aH8nY4.rst new file mode 100644 index 00000000000000..0fcbc90ca11e91 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-10-20-02-30-00.gh-issue-131723.aH8nY4.rst @@ -0,0 +1,3 @@ +Fix :func:`statistics.fmean` with compatible +:class:`~decimal.Decimal` data and weights. Clarify that weighted inputs must +have compatible types for multiplication.