Skip to content

Clamp(value, min, max) returns min when min > max instead of throwing ArgumentException #117

Description

@matt-edmondson

What's wrong

The instance Clamp<TNumber> (PreciseNumber/PreciseNumber.cs:575-582) never checks that min <= max. The static INumber<T>.Clamp at ~line 1713 calls it, so the check is missing there too:

PreciseNumber clampedToMax = this > sigMax ? sigMax : this;
return this < sigMin ? sigMin : clampedToMax;

Reproduced on net10.0:

  • PreciseNumber.Clamp(2, 3, 1) returns 3
  • PreciseNumber.Clamp(5, 3, 1) returns 3

Math.Clamp, decimal.Clamp, int.Clamp and the default INumber<T>.Clamp all throw ArgumentException when min > max.

Why it matters

An inverted range is almost always a caller bug, such as swapped arguments or a computed bound. The BCL reports it loudly. PreciseNumber instead returns a value that satisfies neither bound from the caller's point of view. Generic code written against INumber<T> behaves differently depending on whether T is decimal or PreciseNumber. The existing tests (PreciseNumberTests.cs:68-93, 384-393) only cover valid ranges.

Suggested fix

After converting the bounds, add if (sigMin > sigMax) throw new ArgumentException(...). Mirror the BCL message: "'min' cannot be greater than 'max'".

Acceptance criteria

  • PreciseNumber.Clamp(2, 3, 1) throws ArgumentException, through both the static and the instance overloads.
  • A test covers the inverted range.

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