浮點(diǎn)數(shù)的注意事項(xiàng)

浮點(diǎn)數(shù)判斷相等問(wèn)題

啤酒和飲料

啤酒每罐2.3元,飲料每罐1.9元荡灾。小明買(mǎi)了若干啤酒和飲料,一共花了82.3元瓤狐。
我們還知道他買(mǎi)的啤酒比飲料的數(shù)量少,請(qǐng)你計(jì)算他買(mǎi)了幾罐啤酒。
注意:答案是一個(gè)整數(shù)批幌。請(qǐng)通過(guò)瀏覽器提交答案
不要書(shū)寫(xiě)任何多余的內(nèi)容(例如:寫(xiě)了飲料的數(shù)量,添加說(shuō)明文字等)础锐。

這道題是送分題,很多同學(xué)用通過(guò)暴力破解法這種方法實(shí)現(xiàn)的:

public class 浮點(diǎn)數(shù)1_啤酒和飲料 {
    public static void main(String[] args) {
        for (int a = 0; a < 100; a++)  //a 是啤酒數(shù)量荧缘,b是飲料的數(shù)量皆警,假設(shè)它們的取值范圍都在0 ~ 100
        {
            for (int b = 0; b < 100; b++) {
                if (a * 2.3 + b * 1.9 == 82.3 && a < b)
                    System.out.println(a + "," + b);
            }
        }
    }
}

只不過(guò),犯了一個(gè)大忌——兩個(gè)浮點(diǎn)數(shù)之間不能用“==”來(lái)判斷是否相等截粗。因?yàn)楦↑c(diǎn)數(shù)在計(jì)算式內(nèi)部是采用二進(jìn)制的方式來(lái)表示信姓。因此在計(jì)算機(jī)中0.1+0.2不是等于0.3,而是等于“0.30000000000000004”(不信自己去敲一敲)桐愉。這道題能算出結(jié)果算是你運(yùn)氣好财破。
既然這樣,那我們?nèi)绾蝸?lái)判斷浮點(diǎn)數(shù)是否相等呢从诲?
要判斷浮點(diǎn)數(shù)是否相等左痢,則a-b的絕對(duì)值無(wú)限接近一個(gè)非常小的值。
|a - b| < set系洛,一般set=1E-6(科學(xué)計(jì)數(shù)法俊性,1*10的負(fù)6次方)即可。
由此可以這樣實(shí)現(xiàn):

public class 浮點(diǎn)數(shù)1_啤酒和飲料 {
    public static void main(String[] args) {
        for (int a = 0; a < 100; a++)  //a 是啤酒數(shù)量描扯,b是飲料的數(shù)量定页,假設(shè)它們的取值范圍都在0 ~ 100
        {
            for (int b = 0; b < 100; b++) {
                if (Math.abs(a * 2.3 + b * 1.9 - 82.3) < 1E-10 && a < b)
                    System.out.println(a + "," + b);
            }
        }
    }
}

由于題目給的這些浮點(diǎn)數(shù)都保留一位小數(shù),則可以把所有數(shù)值都乘以10绽诚,變成整數(shù)來(lái)全等判斷:

public class 浮點(diǎn)數(shù)1_啤酒和飲料 {
    public static void main(String[] args) {
        for (int a = 0; a < 100; a++)  //a 是啤酒數(shù)量典徊,b是飲料的數(shù)量,假設(shè)它們的取值范圍都在0 ~ 100
        {
            for (int b = 0; b < 100; b++) {
                if (a * 23 + b * 19 == 823 && a < b)
                    System.out.println(a + "," + b);
            }
        }
    }
}

使用整數(shù)進(jìn)行全等判斷恩够,比浮點(diǎn)數(shù)安全多了卒落。

海盜問(wèn)題

有一群海盜(不多于20人),在船上比拼酒量蜂桶。過(guò)程如下:打開(kāi)一瓶酒儡毕, 所有在場(chǎng)的人平分喝下,有幾個(gè)人倒下了扑媚。再打開(kāi)一瓶酒平分腰湾,又有倒下的雷恃,再次重復(fù)...... 直到開(kāi)了第4瓶酒,坐著的已經(jīng)所剩無(wú)幾费坊,海盜船長(zhǎng)也在其中倒槐。當(dāng)?shù)?瓶酒平分喝下后,大家都倒下了葵萎。等船長(zhǎng)醒來(lái)导犹,發(fā)現(xiàn)海盜船擱淺了。他在航海日志中寫(xiě)到:“......昨天羡忘,我正好喝了一瓶.......奉勸大家谎痢,開(kāi)船不喝酒,喝酒別開(kāi)船......”
請(qǐng)你根據(jù)這些信息卷雕,推斷開(kāi)始有多少人节猿,每一輪喝下來(lái)還剩多少人。
如果有多個(gè)可能的答案漫雕,請(qǐng)列出所有答案滨嘱,每個(gè)答案占一行。
格式是:人數(shù),人數(shù),...
例如,有一種可能是:20,5,4,2,0

思路:這道題關(guān)鍵是船長(zhǎng)的這句話(huà)浸间,“昨天太雨,我正好喝了一瓶”,船上打開(kāi)了4瓶酒魁蒜,每瓶酒向沒(méi)醉的人進(jìn)行平分囊扳。所以,由題意可得兜看,每次平分的酒量相加為1锥咸。
代碼如下:

public class 浮點(diǎn)數(shù)2_海盜問(wèn)題 {
    public static void main(String[] args) {
        int a, b, c, d;  //每一輪剩下的人
        for (a = 20; a >= 1; a--)
            //第一輪,海盜的人不多于20人细移,但至少會(huì)有一人
            for (b = a - 1; b >= 1; b--)
                //每一輪都有人倒下搏予,因此第二輪肯定比第一輪a的人數(shù)少
                for (c = b - 1; c >= 1; c--)
                    //第三輪人數(shù)比第二輪少,但至少有一人
                    for (d = c - 1; d >= 1; d--) {
                        //第四輪人數(shù)比第三輪少弧轧,但至少有一人
                        //船長(zhǎng)四輪都喝了雪侥,每輪都是平分的酒,一共喝了一瓶
                        if (1.0 / a + 1.0 / b + 1.0 / c + 1.0 / d == 1.0)
                            System.out.println(a + "," + b + "," + c + "," + d);
                    }
    }
}

注意:判斷式內(nèi)一定是(1.0/a+1.0/b+1.0/c+1.0/d==1.0)精绎,如果是(1/a+1/b+1/c+1/d==1)速缨,由于1/a是整型,所以1/a為0捺典,不是小數(shù)鸟廓。
但是从祝,上面的代碼忽略了“兩個(gè)浮點(diǎn)數(shù)之間不能用全等來(lái)判斷是否相等襟己∫眨”這個(gè)易錯(cuò)點(diǎn)。

修改的代碼如下:

public class 浮點(diǎn)數(shù)2_海盜問(wèn)題 {
    public static void main(String[] args) {
        int a, b, c, d;  //每一輪剩下的人
        for (a = 20; a >= 1; a--)
            //第一輪擎浴,海盜的人不多于20人员咽,但至少會(huì)有一人
            for (b = a - 1; b >= 1; b--)
                //每一輪都有人倒下,因此第二輪肯定比第一輪a的人數(shù)少
                for (c = b - 1; c >= 1; c--)
                    //第三輪人數(shù)比第二輪少贮预,但至少有一人
                    for (d = c - 1; d >= 1; d--) {
                        //第四輪人數(shù)比第三輪少贝室,但至少有一人
                        //船長(zhǎng)四輪都喝了,每輪都是平分的酒仿吞,一共喝了一瓶
                        if (Math.abs(1.0 / a + 1.0 / b + 1.0 / c + 1.0 / d - 1.0) < 1E-10)
                            System.out.println(a + "," + b + "," + c + "," + d);
                    }
    }
}

這道題滑频,我們還有另一個(gè)判斷的方式,就是在(1/a+1/b+1/c+1/d==1)中唤冈,每項(xiàng)分別乘以(a * b * c * d)
修改的代碼如下:

public class 浮點(diǎn)數(shù)2_海盜問(wèn)題 {
    public static void main(String[] args) {
        int a, b, c, d;  //每一輪剩下的人
        for (a = 20; a >= 1; a--)
            //第一輪峡迷,海盜的人不多于20人,但至少會(huì)有一人
            for (b = a - 1; b >= 1; b--)
                //每一輪都有人倒下你虹,因此第二輪肯定比第一輪a的人數(shù)少
                for (c = b - 1; c >= 1; c--)
                    //第三輪人數(shù)比第二輪少绘搞,但至少有一人
                    for (d = c - 1; d >= 1; d--) {
                        //第四輪人數(shù)比第三輪少,但至少有一人
                        //船長(zhǎng)四輪都喝了傅物,每輪都是平分的酒夯辖,一共喝了一瓶
                        if (b * c * d + a * c * d + a * b * d + a * b * c == a * b * c * d)
                            System.out.println(a + "," + b + "," + c + "," + d);
                    }
    }
}

四舍六入五成雙

Java舍入方式叫“四舍六入五成雙”
規(guī)則:
(1)被修約的數(shù)字小于5時(shí)董饰,該數(shù)字舍去蒿褂;
(2)被修約的數(shù)字大于5時(shí),則進(jìn)位尖阔;
(3)被修約的數(shù)字等于5時(shí)贮缅,要看5前面的數(shù)字,若是奇數(shù)則進(jìn)位介却,若是偶數(shù)則將5舍掉谴供,即修約后末尾數(shù)字都成為偶數(shù);若5的后面還有不為“0”的任何數(shù)齿坷,則此時(shí)無(wú)論5的前面是奇數(shù)還是偶數(shù)桂肌,均應(yīng)進(jìn)位。

舉例永淌,用上述規(guī)則對(duì)下列數(shù)據(jù)保留3位有效數(shù)字:
9.8249=9.82, 9.82671=9.83
9.8350=9.84, 9.8351 =9.84
9.8250=9.82, 9.82501=9.83
從統(tǒng)計(jì)學(xué)的角度崎场,“四舍六入五成雙”比“四舍五入”要科學(xué),在大量運(yùn)算時(shí)遂蛀,它使舍入后的結(jié)果誤差的均值趨于零谭跨,而不是像四舍五入那樣逢五就入,導(dǎo)致結(jié)果偏向大數(shù),使得誤差產(chǎn)生積累進(jìn)而產(chǎn)生系統(tǒng)誤差螃宙,“四舍六入五成雙”使測(cè)量結(jié)果受到舍入誤差的影響降到最低蛮瞄。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市谆扎,隨后出現(xiàn)的幾起案子挂捅,更是在濱河造成了極大的恐慌,老刑警劉巖堂湖,帶你破解...
    沈念sama閱讀 211,265評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件闲先,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡无蜂,警方通過(guò)查閱死者的電腦和手機(jī)伺糠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)斥季,“玉大人退盯,你說(shuō)我怎么就攤上這事⌒嚎希” “怎么了渊迁?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,852評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)灶挟。 經(jīng)常有香客問(wèn)我琉朽,道長(zhǎng),這世上最難降的妖魔是什么稚铣? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,408評(píng)論 1 283
  • 正文 為了忘掉前任箱叁,我火速辦了婚禮,結(jié)果婚禮上惕医,老公的妹妹穿的比我還像新娘耕漱。我一直安慰自己,他們只是感情好抬伺,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布螟够。 她就那樣靜靜地躺著,像睡著了一般峡钓。 火紅的嫁衣襯著肌膚如雪妓笙。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,772評(píng)論 1 290
  • 那天能岩,我揣著相機(jī)與錄音寞宫,去河邊找鬼。 笑死拉鹃,一個(gè)胖子當(dāng)著我的面吹牛辈赋,可吹牛的內(nèi)容都是我干的鲫忍。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼钥屈,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼饲窿!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起焕蹄,我...
    開(kāi)封第一講書(shū)人閱讀 37,688評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎阀溶,沒(méi)想到半個(gè)月后腻脏,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,130評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡银锻,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評(píng)論 2 325
  • 正文 我和宋清朗相戀三年永品,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片击纬。...
    茶點(diǎn)故事閱讀 38,617評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡鼎姐,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出更振,到底是詐尸還是另有隱情炕桨,我是刑警寧澤,帶...
    沈念sama閱讀 34,276評(píng)論 4 329
  • 正文 年R本政府宣布肯腕,位于F島的核電站献宫,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏实撒。R本人自食惡果不足惜姊途,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望知态。 院中可真熱鬧捷兰,春花似錦、人聲如沸负敏。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,740評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)其做。三九已至友扰,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間庶柿,已是汗流浹背村怪。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,967評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留浮庐,地道東北人甚负。 一個(gè)月前我還...
    沈念sama閱讀 46,315評(píng)論 2 360
  • 正文 我出身青樓柬焕,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親梭域。 傳聞我的和親對(duì)象是個(gè)殘疾皇子斑举,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容