From 76747d32b4cd04ef6cce8718120f28f805a865eb Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 2 Sep 2022 12:32:51 +0200 Subject: [PATCH] Handle FP errors in RoundLayoutValueUp. If the `value` passed to `RoundLayoutValueUp` has a floating point precision error (e.g. 79.333333333333343 in the test case) then when it's multiplied by `dpiScale` and rounded up, it will be rounded up to the a value one greater than it should be. Fix this by rounding the initial value to an arbitrary precision of 8 digits. Fixes #8866 --- src/Avalonia.Base/Layout/LayoutHelper.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/Avalonia.Base/Layout/LayoutHelper.cs b/src/Avalonia.Base/Layout/LayoutHelper.cs index 404d19906a..0851dbaea9 100644 --- a/src/Avalonia.Base/Layout/LayoutHelper.cs +++ b/src/Avalonia.Base/Layout/LayoutHelper.cs @@ -251,6 +251,17 @@ namespace Avalonia.Layout { double newValue; + // Round the value to avoid FP errors. This is needed because if `value` has a floating + // point precision error (e.g. 79.333333333333343) then when it's multiplied by + // `dpiScale` and rounded up, it will be rounded up to a value one greater than it + // should be. +#if NET6_0_OR_GREATER + value = Math.Round(value, 8, MidpointRounding.ToZero); +#else + // MidpointRounding.ToZero isn't available in netstandard2.0. + value = Math.Truncate(value * 1e8) / 1e8; +#endif + // If DPI == 1, don't use DPI-aware rounding. if (!MathUtilities.IsOne(dpiScale)) {