在 WPF 應用程式中,開發人員常需要在 Canvas 上隨機放置圖形(如橢圓),並要求座標為 2 的倍數。初期嘗試使用 Random.Next 產生整數,再乘以 2 來達成需求:
Canvas.SetLeft(elli, Math.Round((double)random.Next((int)canvas.Width / 2)) * 2);
Canvas.SetTop(elli, Math.Round((double)random.Next((int)canvas.Height / 2)) * 2);
然而,後續判斷兩個元素座標是否相等時,總是回傳 false。經檢查發現,座標值竟出現 {x=20, y=39.999994} 這類非整數數值。
Random.Next 確實產生整數,但將其指派給 Canvas.Left、Canvas.Top 這類 double 型別屬性時,會發生隱含型別轉換,導致極小的浮點數誤差(如 39.999994)。這是 IEEE 754 浮點數表示法的固有特性,無法完全避免。
不要直接用 == 比較 double,改用差值絕對值小於極小值(如 0.0001)判斷相等:
const double Epsilon = 0.0001;
bool IsEqual(double a, double b) => Math.Abs(a - b) < Epsilon;
將座標轉為字串後比較,可忽略尾端雜訊:
bool IsEqual(double a, double b) => a.ToString("F2") == b.ToString("F2");
若邏輯允許,可在內部用 int 運算,只在最終設定屬性時轉型:
int x = random.Next((int)canvas.Width / 2) * 2;
int y = random.Next((int)canvas.Height / 2) * 2;
Canvas.SetLeft(elli, (double)x);
Canvas.SetTop(elli, (double)y);
雖然屬性仍為 double,但來源為精確整數,誤差機率大幅降低。
int,僅在 UI 繪製時轉型。Point 比較工具方法,統一處理浮點數誤差。掌握浮點數特性,能避免許多難以重現的 UI 定位錯誤,提升 WPF 應用程式的穩定度。