Repository: dotnet/runtime
File: src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt128Tests.cs (C#)

Code before:
            yield return new object[] { (UInt128)0, (UInt128)1, "0000000000000000000000000000000000000000000000000000000000000000" };
            yield return new object[] { (UInt128)1, (UInt128)0, "0000000000000000000000000000000000000000000000000000000000000000" };
            yield return new object[] { (UInt128)2, (UInt128)3, "0000000000000000000000000000000000000000000000000000000000000006" };
            yield return new object[] { UInt128.MaxValue, (UInt128)2, "00000000000000000000000000000001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" };
            yield return new object[] { UInt128.MaxValue, (UInt128)1, "00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" };
            yield return new object[] { UInt128.MaxValue, UInt128.MaxValue, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE00000000000000000000000000000001" };
            yield return new object[] { UInt128.MaxValue, (UInt128)3, "00000000000000000000000000000002FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD" };
            yield return new object[] { new UInt128(0xE8FAF08929B46BB5, 0x26B442D59782BA17), new UInt128(0x26B442D59782BA17, 0xE8FAF08929B46BB5), "23394CF891529663F897F2180AA9D1F6EA183EE8D7CCD26D1EB6255F4A612F43" };
        }

        [Theory]
        [MemberData(nameof(BigMul_TestData))]
        public static void BigMul(UInt128 a, UInt128 b, string result)
        {
            UInt128 upper = UInt128.BigMul(a, b, out UInt128 lower);
            Assert.Equal(result, $"{upper:X32}{lower:X32}");
        }

        [Fact]
        public static void ExplicitConversionToDouble_LargeValue()
        {
            // Value: 309485009821345068741558271 (approx 2^88)
            // This tests the path for values < 2^104 (after fix) or >= 2^88 (before fix)
            UInt128 value = UInt128.Parse("309485009821345068741558271");
            double d = (double)value;
            Assert.Equal(3.094850098213451E+26, d);

            // Value >= 2^104
            // 2^104 = 20282409603651670423947251286016
            // The value is constructed as 2^104 + 2^24 + 1.
            // This tests a value with a 1 at bit 104, a 1 at bit 24, and a 1 at bit 0.
            // The lower bits (24 and 0) should contribute to the sticky bit calculation.
            UInt128 value2 = (UInt128.One << 104) + (UInt128.One << 24) + 1;
            double d2 = (double)value2;
            // Expected: 2^104. 2^24 is far below ULP (2^52).
            double expected2 = 20282409603651670423947251286016.0;
            Assert.Equal(expected2, d2);
        }
    }
}


Review comment (suggestion):
```suggestion
            Assert.Equal(309485009821345068741558271.0, d);
```

Code after:
            yield return new object[] { (UInt128)0, (UInt128)1, "0000000000000000000000000000000000000000000000000000000000000000" };
            yield return new object[] { (UInt128)1, (UInt128)0, "0000000000000000000000000000000000000000000000000000000000000000" };
            yield return new object[] { (UInt128)2, (UInt128)3, "0000000000000000000000000000000000000000000000000000000000000006" };
            yield return new object[] { UInt128.MaxValue, (UInt128)2, "00000000000000000000000000000001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" };
            yield return new object[] { UInt128.MaxValue, (UInt128)1, "00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" };
            yield return new object[] { UInt128.MaxValue, UInt128.MaxValue, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE00000000000000000000000000000001" };
            yield return new object[] { UInt128.MaxValue, (UInt128)3, "00000000000000000000000000000002FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD" };
            yield return new object[] { new UInt128(0xE8FAF08929B46BB5, 0x26B442D59782BA17), new UInt128(0x26B442D59782BA17, 0xE8FAF08929B46BB5), "23394CF891529663F897F2180AA9D1F6EA183EE8D7CCD26D1EB6255F4A612F43" };
        }

        [Theory]
        [MemberData(nameof(BigMul_TestData))]
        public static void BigMul(UInt128 a, UInt128 b, string result)
        {
            UInt128 upper = UInt128.BigMul(a, b, out UInt128 lower);
            Assert.Equal(result, $"{upper:X32}{lower:X32}");
        }

        [Fact]
        public static void ExplicitConversionToDouble_LargeValue()
        {
            // Value: 309485009821345068741558271 (approx 2^88)
            // This tests the path for values < 2^104 (after fix) or >= 2^88 (before fix)
            UInt128 value = UInt128.Parse("309485009821345068741558271");
            double d = (double)value;
            Assert.Equal(309485009821345068741558271.0, d);

            // Value >= 2^104
            // 2^104 = 20282409603651670423947251286016
            // The value is constructed as 2^104 + 2^24 + 1.
            // This tests a value with a 1 at bit 104, a 1 at bit 24, and a 1 at bit 0.
            // The lower bits (24 and 0) should contribute to the sticky bit calculation.
            UInt128 value2 = new(0x0100_0000_0000, 0x0100_0001);
            double d2 = (double)value2;
            // Expected: 2^104. 2^24 is far below ULP (2^52).
            double expected2 = 20282409603651670423947251286016.0;
            Assert.Equal(expected2, d2);
        }
    }
}