Skip to content

Overflow when Fraction instances are created using Numpy integers #133459

@aerobio

Description

@aerobio

Consider the following operations between fractions:

>>> from fractions import Fraction
>>> import numpy as np
>>> np.seterr(all='ignore')

>>> a = Fraction(15.09288707969291)
>>> b = Fraction(24274009, 1604460)
>>> c = Fraction(np.int64(24274009), 1604460)

>>> b == c
True
>>> a - b
Fraction(-8173385384594606777, 225807670566589562880)
>>> a - c
Fraction(3404474268251672442183, 225807670566589562880)

The last two results should be equal.

Numpy integers qualify as Rational in Fraction.__new__() and the Fraction instance uses them internally without modification:

class Fraction(numbers.Rational):
    def __new__(cls, numerator=0, denominator=None, *, _normalize=True):
        [...]
        elif (isinstance(numerator, numbers.Rational) and
            isinstance(denominator, numbers.Rational)):
            numerator, denominator = (
                numerator.numerator * denominator.denominator,
                denominator.numerator * numerator.denominator
                )
        [...]

But they may overflow, as in the example, producing wrong results when np.seterr() is set to warn or ignore.
The workaround for the user is as simple as converting inputs to Python integers, but it's not obvious that the user needs to do so.

A small change in the constructor like this would avoid the problem:

class Fraction(numbers.Rational):
    def __new__(cls, numerator=0, denominator=None, *, _normalize=True):
        [...]
        elif (isinstance(numerator, numbers.Rational) and
            isinstance(denominator, numbers.Rational)):
            numerator, denominator = (
                int(numerator.numerator) * int(denominator.denominator),
                int(denominator.numerator) * int(numerator.denominator)
                )
        [...].

CPython versions tested on:

3.10, 3.12, 3.13

Operating systems tested on:

Linux

Metadata

Metadata

Assignees

No one assigned

    Labels

    type-bugAn unexpected behavior, bug, or error

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions