Skip to content

random.Random.gammavariate loops indefinitely for large finite alpha #158745

Description

@augusto-rehfeldt

Bug report

Bug description:

Documented behaviour: Random.gammavariate docstring: "Gamma distribution. Not the gamma function!" and "Conditions on the parameters are alpha > 0 and beta > 0."

Expected: Terminate and return a gamma-distribution sample for these valid finite parameters.

Actual: Loops indefinitely for alpha=1e308 and beta=1e-308 because overflow creates a NaN acceptance value.

import random
import math

args = (1e308, 1e-308, 0)
alpha, beta, seed = args
if not (math.isfinite(alpha) and alpha > 0 and
        math.isfinite(beta) and beta > 0 and
        math.isfinite(alpha * beta)):
    print("REFUTATION REJECTED:", "invalid input", args)
else:
    class DrawLimit(Exception):
        pass

    class BoundedRandom(random.Random):
        draws = 0

        def random(self):
            self.draws += 1
            if self.draws > 512:
                raise DrawLimit
            return super().random()

    # Distribution moments, not a seed-dependent reference implementation.
    expected = dict(behavior="terminate with a gamma sample",
                    mean=alpha * beta,
                    standard_deviation=math.sqrt(alpha) * beta)
    try:
        actual = BoundedRandom(seed).gammavariate(alpha, beta)
    except DrawLimit as exc:
        tb = exc.__traceback__
        while tb and tb.tb_frame.f_code.co_name != "gammavariate":
            tb = tb.tb_next
        state = tb.tb_frame.f_locals if tb else {}
        # These loop invariants force r = bbb + ccc*v - x to NaN
        # on every eligible draw, so neither acceptance test can pass.
        trapped = (state.get("ainv") == math.inf and
                   state.get("ccc") == math.inf and
                   state.get("v") == 0 and
                   state.get("x") == alpha and
                   math.isnan(state.get("r", 0)))
        if trapped:
            print("REFUTATION CONFIRMED:", args,
                  "actual =", "nontermination: invariant NaN acceptance value",
                  "expected =", expected)
        else:
            print("REFUTATION REJECTED:", "draw limit alone is inconclusive", args)
    except Exception as exc:
        print("REFUTATION CONFIRMED:", args,
              "actual =", repr(exc), "expected =", expected)
    else:
        print("REFUTATION REJECTED:", args, "returned", actual,
              "; one sample cannot establish a distributional defect")

Output on Python 3.14.6 (Windows-11-10.0.26220-SP0), standard library random:

REFUTATION CONFIRMED: (1e+308, 1e-308, 0) actual = nontermination: invariant NaN acceptance value expected = {'behavior': 'terminate with a gamma sample', 'mean': 0.9999999999999999, 'standard_deviation': 1e-154}

This report was found and written by an automated property-testing tool I run (bugforge). The reproducer above was executed and its output is pasted unedited; no person reviewed the report before it was filed. The search script is in https://github.com/augusto-rehfeldt/bugforge-results/tree/main/random-20261003-101511-c3

CPython versions tested on:

3.14

Operating systems tested on:

Windows

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions