Skip to content

Divide rounds instead of returning the exact result when a non-2/5 denominator factor cancels against the numerator #100

Description

@matt-edmondson

What's wrong

Divide(PreciseNumber, PreciseNumber, int significantDigits)'s XML doc and TestDivideIsExactWhenTheQuotientTerminates both state the contract: a quotient that terminates is exact regardless of significantDigits, and terminates whenever the reduced denominator is a product of twos and fives. But TryDivideExactly (PreciseNumber/PreciseNumber.cs, ~lines 1485-1512) factors 2s and 5s out of the raw denominator only — it never reduces by GCD(numerator, denominator) first. So whenever the denominator's non-2/5 part is fully cancelled by the numerator, the exact path is skipped and the division falls through to lossy DivideToPrecision.

Why it matters (failure scenario)

PreciseNumber.Divide(91.ToPreciseNumber(), 7.ToPreciseNumber(), 1). 91/7 = 13 exactly (7 has no factor of 2 or 5, so TryDivideExactly returns false even though 91 = 7×13). Falling through to DivideToPrecision with significantDigits=1, it scales, divides to get 130, then rounds to 1 significant digit → 10, not the exact 13 the documented contract requires. All existing test cases in TestDivideIsExactWhenTheQuotientTerminates use denominators that are already pure powers of 2/5 (2,4,5,8,10,16,20,25), so this gap is untested. It's invisible at the default (generous) precision, since padding zeros always divide out cleanly there — it only surfaces when a caller explicitly asks for fewer significant digits than the true exact answer needs.

Suggested fix / acceptance criteria

In TryDivideExactly, reduce by g = BigInteger.GreatestCommonDivisor(BigInteger.Abs(numerator), denominator) (dividing both numerator and denominator by g) before testing the remaining denominator for factors of 2 and 5. Add a regression test covering Divide(91, 7, 1) == 13.

Activity

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

Metadata

Metadata

Labels

bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions