PALMisLIFE 討論區

搜索
鹹魚爸魅力四射舞蹈教室
查看: 23012|回復: 6

[JAVA] [問題]javascript 求餘數

[複製鏈接]

181

主題

5

好友

2509

積分

超敗家的白爛長笛手

  • TA的每日心情
    郁悶
    2013-4-6 01:41
  • 簽到天數: 4 天

    連續簽到: 1 天

    [LV.2]偶爾看看I

    文章
    2201
    發表於 2008-5-28 11:26 |顯示全部樓層
    平常工作多半是寫 C#/VB.Net 為主,幾乎不太寫 javascript 的,有也多半只是用來控制畫面的顯示項而已XD
    就在剛剛,遇到一個很奇妙的情況


    1. var iAmount = 920;
    2. var a = iAmount % 0.92;
    3. var b = iAmount * 100 % 92;
    4. var c = parseInt(iAmount / 0.92);
    5. var d = (a==0)?(c):(c+1);
    複製代碼


    為什麼 b==0 而 a!=0
    原本是要由 a 求得餘數,再來計算 d 值。但程式結果一直不正確,tracking 後竟然發現 a = 0.9199999999999601,然後才異想天開,改成 b 的算式,噗~結果就正確了,因為 b 確實是為 0 的XD

    我想問,這是什麼原因呢。謝謝各位前輩先

    PS: runs on Windows Server 2003,IE7/FF2

    [ 本文最後由 小賤健 於 2008-5-28 13:11 編輯 ]

    21

    主題

    0

    好友

    518

    積分

    該用戶從未簽到

    文章
    398
    發表於 2008-5-28 13:30 |顯示全部樓層

    Re: javascript 求餘數

    Update: Javascript 應該是用「倍精準」的浮點數而非「單精準」,因此稍微修改了一下數字)

    我倒覺得很奇怪:因為我從來沒想過用浮點數去取餘數。
    (因為我最熟的 C 是不能這麼做的)

    然後,你這個問題是發生在電腦裡的二進位浮點數表示法。
    依現在一般通用的浮點數表示法(IEEE標準),0.92 會是一個「循環小數」,而非精確的一個數。
    化成 10 進位來看的話,會是 0.92000000000000004。
    所以 920 % 0.92000000000000004 是除不盡的。

    所以,如果你做個實驗,
    var b = iAmount*100 % (0.92 * 100),b 也不會是 0。

    至於為什麼 0.92 會變成 0.92000000000000004.....
    這故事很長,得用另一篇文章去講。
    你真的想聽嗎? :p

    可以參考下面兩個 URL:
    http://www.ods.com.ua/win/eng/web-tech/js/htm/07-01.phtml
    http://zh.wikipedia.org/wiki/IEEE_754

    [ 本文最後由 closer 於 2008-5-28 14:19 編輯 ]
    已有 1 人評分分享 收起 理由
    小賤健 + 10 Great Reference!

    總評分: 分享 + 10   查看全部評分

    回復

    使用道具 舉報

    181

    主題

    5

    好友

    2509

    積分

    超敗家的白爛長笛手

  • TA的每日心情
    郁悶
    2013-4-6 01:41
  • 簽到天數: 4 天

    連續簽到: 1 天

    [LV.2]偶爾看看I

    文章
    2201
    發表於 2008-5-28 18:17 |顯示全部樓層

    Re: [問題]javascript 求餘數

    至於為什麼 0.92 會變成 0.92000000000000004.....
    這故事很長...

    願聞其詳
    C 我已經忘光光了。
    而 C++ / C#我確是沒有這層限制了
    回復

    使用道具 舉報

    11

    主題

    1

    好友

    485

    積分

    該用戶從未簽到

    文章
    537
    發表於 2008-5-28 18:25 |顯示全部樓層

    Re: Re: [問題]javascript 求餘數

    原文由 小賤健 於 2008-5-28 18:17 發表

    願聞其詳
    C 我已經忘光光了。
    而 C++ / C#我確是沒有這層限制了


    C++應該還是有這個限制的,主要在於記憶體中的表示方式。
    C#的話,除非是用decimal,不然,應該還是會由於相同的原因,發生類似的問題。
    例如最常見的例子就是:
    float delta = 0.1d;
    float sum = 0.0d;
    for(int i=0; i < 10; i ++){
       sum += delta;
    }
    if(sum == 1.0d)
       printf("equal";
    else
      printf("not equal";

    [ 本文最後由 zombie 於 2008-5-28 18:29 編輯 ]
    已有 1 人評分分享 收起 理由
    小賤健 + 10 Great Reference!

    總評分: 分享 + 10   查看全部評分

    If something is ugly or hard, it is wrong

    我的Blog: http://grave.dyndns.org/blog/zombie/
    回復

    使用道具 舉報

    21

    主題

    0

    好友

    518

    積分

    該用戶從未簽到

    文章
    398
    發表於 2008-5-28 22:39 |顯示全部樓層

    Re: Re: [問題]javascript 求餘數

    原文由 小賤健 於 2008-5-28 18:17 發表

    願聞其詳
    C 我已經忘光光了。
    而 C++ / C#我確是沒有這層限制了


    這是浮點數表示法的限制,不是語言的限制。
    除非你用的語言非常高階,會幫你做很多事情、用自己的方法表示小數(例如 VB 和 C# 的 "decimal" 型別),
    否則在現代的 CPU 上處理浮點數 (floating-point),都會遇上這樣的問題。

    原本是想詳細解說一下 IEEE 754 的內容,但真的要詳細討論的話會太複雜。
    尤其是 IEEE 754 用了一些方便電腦實作的技巧,要用人腦理解就更麻煩一點。
    所以就簡單講一下概念好了。

    我們從十進位的浮點數開始看:

    12.34

    這個很簡單,小學畢業就知道它是什麼意思。
    我們如果用科學一點的方法來表示它,它就是:

    1 * ( 10 ^ 1) + 2 * (10 ^ 0) + 3 * (10 ^ (-1)) + 4 * (10 ^ (-2))

    "x ^ y" 表示 "x 的 y 次方"

    10 的 -1 次方就是 1/10,也就是 0.1。這個是高中數學。 :p

    好,那麼,二進位的浮點數其實也是類似的觀念。所以下面這個數字:

        1010.1101b

    化成十進位來看的話,就是

    1 * (2^3) + 0 * (2^2) + 1 * (2^1) + 0 * (2^0) + 1 * (2^(-1)) + 1 * (2^(-2) + 0 * (2^(-3)) + 1 * (2^(-4))
    = 8 + 2 + 1/2 + 1/4 + 1/16
    = 10.8125

    正因為二進位的小數部份是由「2 的 n 次方之一」組成的,所以並不是所有的「十進位有限小數」都能精確地轉成「二進位有限小數」。
    例如 0.2 就只能變成:

    0.001100110011........b

    上面的這個例子轉成十進位會變成 0.199951171875。
    如果再取更多位數的話會更精確。

    所以結論是:浮點數是個很不精確的東西。 XDDDDD

    像是銀行的帳就絕對不能用浮點數處理!
    這也是為什麼 VB 和 C# 會有 "decimal" 這樣的型別。

    有問題再討論.....如果你還有興趣的話。
    已有 1 人評分分享 收起 理由
    小賤健 + 10 我很贊同這篇文章

    總評分: 分享 + 10   查看全部評分

    回復

    使用道具 舉報

    181

    主題

    5

    好友

    2509

    積分

    超敗家的白爛長笛手

  • TA的每日心情
    郁悶
    2013-4-6 01:41
  • 簽到天數: 4 天

    連續簽到: 1 天

    [LV.2]偶爾看看I

    文章
    2201
    發表於 2008-5-28 22:59 |顯示全部樓層

    Re: [問題]javascript 求餘數

    有問題再討論...

    經 closer 兄清晰的解說,我有明白了

    然後也有去翻了一下 MSDN(http://msdn.microsoft.com/en-us/library/se0w9esz(VS.80).aspx),它也有相關的說明。
    平時不太有機會碰到這方面的數值分析,再加上自己寫 code 的習慣(C#/VB),也都是採用比較嚴格的強型別定義,所以上述的問題也都沒碰到過。要不是今天得用 javascript 來處理,我大概這輩子都不會記得有這樣的限制吶@_@

    以上。多謝 closer、zombie 二位的說明,多謝多謝啊

    ---
    而至於 closer 提及的銀行帳務的數值處理,就之前處理過某大銀行的經驗,是採用大數陣列的方式來運算數字的。

    [ 本文最後由 小賤健 於 2008-5-28 23:17 編輯 ]
    回復

    使用道具 舉報

    11

    主題

    1

    好友

    485

    積分

    該用戶從未簽到

    文章
    537
    發表於 2008-5-28 23:56 |顯示全部樓層

    Re: Re: [問題]javascript 求餘數

    原文由 小賤健 於 2008-5-28 22:59 發表

    經 closer 兄清晰的解說,我有明白了

    然後也有去翻了一下 MSDN(http://msdn.microsoft.com/en-us/library/se0w9esz(VS.80).aspx),它也有相關的說明。
    平時不太有機會碰到這方面的數值分析,再加上 ...


    補充一下,在資料庫,也會有因為相同原因所造成的問題,所以,才會有類似oracle的decimal型別的出現,
    這個是設計資料庫的時候需要注意的地方,不然,每個月光為了追那個一元五角的,就追到瘋掉了。
    已有 1 人評分分享 收起 理由
    小賤健 + 10 說也奇怪,DB這部份我倒是知道要去留意:P

    總評分: 分享 + 10   查看全部評分

    If something is ugly or hard, it is wrong

    我的Blog: http://grave.dyndns.org/blog/zombie/
    回復

    使用道具 舉報

    您需要登錄後才可以回帖 登錄 | 免費註冊

    與站長聯繫| PALMisLIFE 掌上生活      下載:更快、更棒、更好玩

    GMT+8, 2024-3-29 21:56 , Processed in 0.055383 second(s), 32 queries , Gzip On.

    Powered by Discuz!

    © 2001-2012 Comsenz Inc. style by eisdl

    回頂部