none
小數點捨入問題 RRS feed

  • 問題

  • 我閱讀msdn好幾次,就是看不懂Round的用法,因此要請大大指點迷津。

    1.Math.Round(1.51) 此方法沒有指定小數位數,因此會取整數,小數若大於5就會捨入,整數 + 1,因此本例答案為 2,若是Math.Round(1.5),答案是1,對不對?

    2.Math.Round(2.155, 2) 此方法指定小數要兩位,小數是如何捨位?

       a. Math.Round(2.155, 2) = 2.15

       b. Math.Round(4.155, 2) = 4.16

       這兩方法小數都相同,為什麼小數捨入結果不同?

    請指導,但拜託不要叫我看msdn說明,我看了又看就是不懂,謝謝

    2013年2月23日 上午 02:25

解答

  • 您好,
    在msdn上有寫說因為「這是因為此方法在內部將value以10的數字,並在此情況下有而失去精度乘法運算。」,
    你可以用反組譯程式看一下Math.Round,可看到「Math.Round 方法 (decimal, Int32) 與 Math.Round 方法 (Double, Int32)」是呼叫不同的Method!
    因為double是非精準數值,所以Round時,會先轉成10進位,所導致的問題。
    所以您如果數值需要精準計算的話,建議您要使用decmial。
    在DB的欄位設計也是一樣哦! 如果您是放金額的話,資料型態千萬別用非精準的型態,如float等等。

    以上說明若有錯誤請指教,謝謝。
    亂馬客blog: http://www.dotblogs.com.tw/rainmaker/

    • 已提議為解答 Alex_Lee 2013年2月23日 上午 04:23
    • 已標示為解答 小玩熊 2013年2月23日 上午 08:54
    2013年2月23日 上午 03:43
  • Hi,

    1.你可以搭配參閱[.NET Concept][C#][VB.NET]四捨六入五成雙

    若小數為5,則會四捨六入五成雙

    所以Math.Round(1.5)也是2

    這用程式跑一次就知道了

    2.應該是浮點數精準度的問題...


    謙卑學習,持之以恆,才能不斷的Level Up http://www.dotblogs.com.tw/larrynung/


    2013年2月23日 上午 03:09

所有回覆

  • 您好,
    如果您要精準的話,資料型態請使用decimal哦!
    decimal a = Math.Round((decimal)2.155, 2); // 2.16
    decimal b = Math.Round((decimal)4.155, 2); // 4.16
    Math.Round 方法 (decimal, Int32)是call decimal.Round

    如果使用double的話,它是非精準數值。
    double c = Math.Round((double)2.155, 2); // 2.15
    double f = Math.Round((double)4.155, 2); // 4.16
    Math.Round 方法 (Double, Int32)是Call  InternalRound 

    呼叫者注意事項
    由於將十進位值表示為浮點數,或者對浮點數值執行算數運算可能導致精確度喪失,因此在某些情況下,Round(Double, Int32) 方法可能無法將中點值四捨五入到最接近 digits 小數點位置中的偶數值。下列範例說明這個程序,其中 2.135 會捨入為 2.13 而不是 2.14。這是因為此方法在內部將value以 10的數字,並在此情況下有而失去精度乘法運算。

    Why does Math.Round(2.5) return 2 instead of 3 in C#?


    以上說明若有錯誤請指教,謝謝。
    亂馬客blog: http://www.dotblogs.com.tw/rainmaker/




    • 已編輯 亂馬客 2013年2月23日 上午 03:14
    • 已提議為解答 ThankfulHeart 2013年2月23日 上午 05:13
    2013年2月23日 上午 02:56
  • Hi,

    1.你可以搭配參閱[.NET Concept][C#][VB.NET]四捨六入五成雙

    若小數為5,則會四捨六入五成雙

    所以Math.Round(1.5)也是2

    這用程式跑一次就知道了

    2.應該是浮點數精準度的問題...


    謙卑學習,持之以恆,才能不斷的Level Up http://www.dotblogs.com.tw/larrynung/


    2013年2月23日 上午 03:09
  • 1. 感謝亂馬客大大說明。

    2. 就以double型別來看,我想知道的是答案為什麼會是2.15與4.16,捨入的結果為何不同。

        double c = Math.Round((double)2.155, 2); // 2.15
        double f = Math.Round((double)4.155, 2); // 4.16

    我看了幾次msdn的說明,是因小數5為中間值的關係,但捨入原則我看不懂。

    謝謝

    2013年2月23日 上午 03:14
  • Hi,

    捨入原則我那回應有看嗎?

    簡單說在5的時候是看捨入跟進位哪個可讓數值變偶數

    而你那邊會變2.15跟4.16是因為浮點數的精準度問題

    雖然你看到的是2.15

    但在電腦中它可能是2.1499999999

    所以會有誤差產生

    你可以換用Math.Round(4.155 - 2, 2)試試

    可能可以產生不一樣的效果


    謙卑學習,持之以恆,才能不斷的Level Up http://www.dotblogs.com.tw/larrynung/

    • 已提議為解答 Alex_Lee 2013年2月23日 上午 04:23
    2013年2月23日 上午 03:37
  • 您好,
    在msdn上有寫說因為「這是因為此方法在內部將value以10的數字,並在此情況下有而失去精度乘法運算。」,
    你可以用反組譯程式看一下Math.Round,可看到「Math.Round 方法 (decimal, Int32) 與 Math.Round 方法 (Double, Int32)」是呼叫不同的Method!
    因為double是非精準數值,所以Round時,會先轉成10進位,所導致的問題。
    所以您如果數值需要精準計算的話,建議您要使用decmial。
    在DB的欄位設計也是一樣哦! 如果您是放金額的話,資料型態千萬別用非精準的型態,如float等等。

    以上說明若有錯誤請指教,謝謝。
    亂馬客blog: http://www.dotblogs.com.tw/rainmaker/

    • 已提議為解答 Alex_Lee 2013年2月23日 上午 04:23
    • 已標示為解答 小玩熊 2013年2月23日 上午 08:54
    2013年2月23日 上午 03:43
  • 感謝諸位大大的說明,Math.Round還可以配合MidpointRounding.ToEven與MidpointRounding.ToEven使用,這兩個參數的差異我也霧殺殺,是否可以請大大一併指導。謝謝,謝謝。
    2013年2月23日 上午 07:32
  • 您好,

    msnd上有說明跟example,您可以參考看看哦!

    MidpointRounding 列舉型別

    Math.Round(decimal, Int32) 與 Math.Round(Double, Int32)


    以上說明若有錯誤請指教,謝謝。
    亂馬客blog: http://www.dotblogs.com.tw/rainmaker/

    2013年2月23日 上午 08:09