From 84dd26a57ba31bfb027c78719cda26fd378891bb Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 26 Sep 2026 17:27:33 +0000 Subject: [PATCH] Count trailing zeros in IsEvenInteger and IsOddInteger Trailing zeros are stored in the exponent, so 10 is significand 1 at exponent 1. The parity checks read only the significand, so every multiple of 10 whose significand was odd (10, 30, 100, ...) reported as odd. Any positive exponent makes the value a multiple of 10 and therefore even; only a value at exponent 0 takes its parity from the significand. Fixes ktsu-dev/PreciseNumber#104 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_018AEYBNCRr6chFLiZDv1MVj --- PreciseNumber.Test/PreciseNumberTests.cs | 36 ++++++++++++++++++++++++ PreciseNumber/PreciseNumber.cs | 14 +++++++-- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/PreciseNumber.Test/PreciseNumberTests.cs b/PreciseNumber.Test/PreciseNumberTests.cs index 10ea1d1..ae97b6b 100644 --- a/PreciseNumber.Test/PreciseNumberTests.cs +++ b/PreciseNumber.Test/PreciseNumberTests.cs @@ -543,6 +543,42 @@ public void TestIsOddInteger() Assert.IsFalse(PreciseNumber.IsOddInteger(two), "Two should not be an odd integer"); } + // Trailing zeros are stored in the exponent, so 10 is significand 1 at exponent 1. The parity + // checks used to read only the significand, which made every multiple of 10 look odd. + + [TestMethod] + [DataRow(10)] + [DataRow(100)] + [DataRow(30)] + [DataRow(-20)] + [DataRow(1000000)] + public void TestIsEvenIntegerForMultiplesOfTen(int value) + { + PreciseNumber number = value.ToPreciseNumber(); + Assert.IsTrue(PreciseNumber.IsEvenInteger(number), $"{value} should be an even integer"); + Assert.IsFalse(PreciseNumber.IsOddInteger(number), $"{value} should not be an odd integer"); + } + + [TestMethod] + public void TestParityOfASumWithTrailingZero() + { + PreciseNumber sum = 7.ToPreciseNumber() + 3.ToPreciseNumber(); + Assert.IsTrue(PreciseNumber.IsEvenInteger(sum), "7 + 3 should be an even integer"); + Assert.IsFalse(PreciseNumber.IsOddInteger(sum), "7 + 3 should not be an odd integer"); + } + + [TestMethod] + [DataRow(1)] + [DataRow(-3)] + [DataRow(21)] + [DataRow(1001)] + public void TestIsOddIntegerForOddValues(int value) + { + PreciseNumber number = value.ToPreciseNumber(); + Assert.IsTrue(PreciseNumber.IsOddInteger(number), $"{value} should be an odd integer"); + Assert.IsFalse(PreciseNumber.IsEvenInteger(number), $"{value} should not be an even integer"); + } + [TestMethod] public void TestIsPositive() { diff --git a/PreciseNumber/PreciseNumber.cs b/PreciseNumber/PreciseNumber.cs index fc17624..ee217fb 100644 --- a/PreciseNumber/PreciseNumber.cs +++ b/PreciseNumber/PreciseNumber.cs @@ -1045,7 +1045,13 @@ public static PreciseNumber Abs(PreciseNumber value) => public static bool IsComplexNumber(PreciseNumber value) => !IsRealNumber(value); /// - public static bool IsEvenInteger(PreciseNumber value) => IsInteger(value) && value.Significand.IsEven; + /// + /// Trailing zeros are stored in , so 10 is significand 1 at exponent 1. The + /// significand's parity is the value's only at exponent 0; any positive exponent makes the value a + /// multiple of 10, and so even. + /// + public static bool IsEvenInteger(PreciseNumber value) => + IsInteger(value) && (value.Exponent > 0 || value.Significand.IsEven); /// public static bool IsFinite(PreciseNumber value) => true; @@ -1077,7 +1083,11 @@ public static bool IsInteger(PreciseNumber value) => public static bool IsNormal(PreciseNumber value) => true; /// - public static bool IsOddInteger(PreciseNumber value) => IsInteger(value) && !value.Significand.IsEven; + /// + /// Only a value at exponent 0 can be odd, for the reason given on . + /// + public static bool IsOddInteger(PreciseNumber value) => + IsInteger(value) && value.Exponent == 0 && !value.Significand.IsEven; /// public static bool IsPositive(PreciseNumber value) =>