浮點(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é)果受到舍入誤差的影響降到最低蛮瞄。