What's wrong
The even and odd tests only look at the parity of the stored significand:
// PreciseNumber/PreciseNumber.cs:1048
public static bool IsEvenInteger(PreciseNumber value) => IsInteger(value) && value.Significand.IsEven;
// PreciseNumber/PreciseNumber.cs:1080
public static bool IsOddInteger(PreciseNumber value) => IsInteger(value) && !value.Significand.IsEven;
The sanitizing constructor strips trailing zeros. So 10 is stored as significand 1 at exponent 1, and 100 as 1 at exponent 2. The significand's parity is only the value's parity when Exponent == 0. When Exponent > 0 the value is a multiple of 10, so it is always even.
Failure scenario
PreciseNumber.IsEvenInteger(PreciseNumber.Parse("10", null)); // False (expected True)
PreciseNumber.IsOddInteger(PreciseNumber.Parse("10", null)); // True (expected False)
PreciseNumber.IsOddInteger(PreciseNumber.Parse("100", null)); // True
PreciseNumber.IsEvenInteger(10.ToPreciseNumber()); // False
PreciseNumber.IsOddInteger(PreciseNumber.Parse("7", null) + PreciseNumber.Parse("3", null)); // True
Any generic INumber<T> code that branches on T.IsEvenInteger or T.IsOddInteger gets the wrong answer for 10, 30, 50, 100, 1000 and so on. Sign handling for negative bases in a generic power routine is one example. The existing tests only check 1 and 2, so they do not catch this.
Suggested fix
public static bool IsEvenInteger(PreciseNumber value) =>
IsInteger(value) && (value.Exponent > 0 || value.Significand.IsEven);
public static bool IsOddInteger(PreciseNumber value) =>
IsInteger(value) && value.Exponent == 0 && !value.Significand.IsEven;
Add tests for 10, 100, 30 and -20.
What's wrong
The even and odd tests only look at the parity of the stored significand:
The sanitizing constructor strips trailing zeros. So
10is stored as significand1at exponent1, and100as1at exponent2. The significand's parity is only the value's parity whenExponent == 0. WhenExponent > 0the value is a multiple of 10, so it is always even.Failure scenario
Any generic
INumber<T>code that branches onT.IsEvenIntegerorT.IsOddIntegergets the wrong answer for 10, 30, 50, 100, 1000 and so on. Sign handling for negative bases in a generic power routine is one example. The existing tests only check 1 and 2, so they do not catch this.Suggested fix
Add tests for 10, 100, 30 and -20.