簡體   English   中英

如何在C#中處理精度

[英]How to deal with precision in C#

查找兩點之間的積分點數的奇異精度行為不包括:

我正在為此編寫一個算法(偽)。

給定x1,y1和x2,y2

我計算了double m,其中m是以(double)(y2-y1)/(x2-x1)給出的線段的斜率,然后我計算了double c,其中c是以y1-(m * x1)給出的y截距

然后對於i = Min(x1,x2)i <Max(x1,x2)對於j = Min(y1,y2)j <Max(y1,y2)如果j =(m * i)+ c,則++

最后,返回結果-1

該代碼適用於某些測試用例,但在其他一些用例上卻失敗,例如,當兩個端點彼此垂直時,我必須處理m的無窮大,而處理c的NaN情況。 但是,一個特殊的案例引起了我的注意,分別針對x1,y1和x2,y2的測試案例43,38,17,6。

運行代碼j從6開始,而i從17開始,所以這一點肯定在線段上,即使我不應該將其計算在內,因為這是一個終點。 這個值i,j!=(m * i)+ c = 5.9999999999 ...而不是6,這是什么奇怪?這怎么可能? 我在哪里為此失去精度? 更重要的是,我如何失去精度?

碼:

        int cnt = 0;
        double i, j;
        double m = (double)(y2 - y1) / (x2 - x1);
        double c = y1 - (m * x1);
        for (i = Math.Min(x1, x2); i <= Math.Max(x1, x2); i++)
        {
            for (j = Math.Min(y1, y2); j <= Math.Max(y1, y2); j++)
            {
                if (j == (m * i) + c||double.IsInfinity(m) && double.IsNaN(c))
                    cnt++;
            }
        }
        return cnt - 2;

所以我將所有變量都更改為十進制,但是不幸的是,我仍然無法通過測試。 但我認為我已經將其縮小到這一點:小數m =(小數)(y2-y1)/(x2-x1);

mcdouble ,因此(m*i)+c將返回double 但是j是一個int 因此,您正在將整數與雙精度進行比較。 給定浮點表示形式 ,在進行直接比較時,這將成為一個問題。 您需要將比較的右側強制轉換為整數,或者進行某種非精確比較。 或者,您可以使用非浮點精度的內容,例如decimal ,這不會顯示此問題。

雙打不能精確。 它們僅精確到一定位數。 請記住,它們使用內部格式以字節存儲。 這將不可避免地引起一些精度誤差。

甚至更糟的是,即使不進行計算,也無法精確存儲您放入雙精度值的某些值。

使您知道的示例:可以在此處測試將1.94分配給double變量,結果將為: 1.939999999999999946709294817992486059665679931640625

這是錯誤的做法,並且注定無法將兩個浮點數與相等運算符進行比較。

有關浮點數的重要閱讀: 每位計算機科學家都應了解的浮點算法

將無限多個實數壓縮為有限數量的位需要近似表示。 盡管有無限多個整數,但是在大多數程序中,整數計算的結果可以存儲在32位中。 相反,在給定固定位數的情況下, 大多數使用實數的計算將產生無法使用那么多位數精確表示的數量。 因此,浮點計算的結果通常必須四舍五入,以重新適合其有限表示形式。 舍入誤差是浮點計算的特征。

作為解決方案,如果您真的要比較,可以在比較結果之前用Math.round(x, decimals)敏感地舍入結果。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM