人人上看到的。。。
。。。背景为长春赛区的D和跟nzk,AC的一系列讨论。。。
以下语言环境为g++
猜猜看这些代码的输出结果?
printf("%0.1lf\n", 0.05);
printf("%0.1lf\n", 0.25);
printf("%0.1lf\n", 0.75);
printf("%0.2lf\n", 0.025);
printf("%0.2lf\n", 0.015);
printf("%0.2lf\n", 0.125);
有人可能会说了这不是很简单的么。。。四舍五入啊。。。
但是实际上。。。
答案分别是:
0.1
0.2
0.8
0.03
0.01
0.12
C++的输出不是四舍五入,是所谓的“四舍六入五留双”!。
也就是对于5,是看5的前面一位,如果是奇数就进位,偶数就退位。
那为什么第一行会是0.1?
仔细看一下0.05
printf("%0.20lf\n", 0.05);
输出是0.05000000000000000278
再看看0.015。。。。
printf("%0.20lf\n", 0.015);
0.01499999999999999944
这是因为电脑是用2进制存数的,而0.05不是纯2进制小数,所以会有误差,而C++的转化方式中是误差是不确定的,从而造成了四舍五入的错觉。
可以发现0.25和0.75和0.125都满足条件。。。
由于这个性质。。。在大部分情况下***5的输出在C++中,只要这个小数不是纯二进制小数,很多时候都表现的跟四舍五入一样!!但其实不是的啊亲!!!
所以很多时候我们+eps来解决这个问题。。。但是遇到纯二进制小数这反而又会跪啊。。。。太无语了。。。
也就是说平常我们以为的四舍五入都是十进制转二进制带来的错觉啊!!!!
更加糟糕的是。。。如果标程0.015输出0.01,0.75输出0.8,0.25输出0.2,0.05输出0.1。。。
尼玛没有任何一种舍入方式是完全符合这种的啊!!!!!!!!!
除非你说是考虑了C++特殊国情的奇葩舍入方式啊!!!!!
尼玛。。。
注意到+eps,-eps都无法解决这个问题。
考虑长春赛区的D题。。。
比如case
1
1 -5 -2 -6 9
答案是
(-INF, 1.03125000000000000000]
非常遗憾的是这是一个纯二进制小数,也就是说答案按照C++的round应该是1.0312。。+EPS就会变成1.0313。。。就死光了。。。
但是。。。round的定义在不同的语言中是不一样的。。。
至少在我所认识的common sense里都是指四舍五入所以这纯坑爹好么????????
momo AC。。。比赛的时候就这个坑了。。。
经过AC和nzk的测试。。。其它任何一种舍入方式都不能通过这题的数据。。。
upd:
System.out.format("%.1f", 0.25); 的输出是0.3。。。也就是Java是纯四舍五入的。。。。。ruby跟C++一样1.9.3p194 :002 > print "%0.1f" % [0.25]
0.2 => nil
1.9.3p194 :003 > print "%0.1f" % [0.75]
0.8 => nil