1
bombless 2015-01-21 17:37:24 +08:00
你看,你这就属于学艺不精了……
我 C 语言一样复现给你看 #include <stdio.h> double round(double); int main() { double a = 57; double b = .57 * 100; double c = round(.57 * 100); printf("%f, %f, %d, %d", b, c, a == b, a == c); return 0; } 输出是 57.000000, 57.000000, 0, 1 你需要学习的是浮点数,不是 PHP |
2
eslizn 2015-01-21 17:37:32 +08:00
round返回的是浮点啊,被蠢哭
|
4
tabris17 2015-01-21 18:03:19 +08:00
你看看 $b == $c 的结果,会有惊喜
|
6
alex321 2015-01-21 18:05:52 +08:00
|
8
bombless 2015-01-21 18:12:28 +08:00 1
@laoyuan 不是高级不高级的……
round之后就是整数了。 浮点数就是二进制表示的小数。你打印出来的是十进制的小数。 所以接下来我就按二进制小数和十进制小数讲解了。 另外我说的都是有限小数,下面看的时候要把二进制小数理解成二进制表示的有限小数。十进制的情况也同理。 只有它是整数的时候,二进制才能和十进制表示无损地互换——就是说,可以把二进制小数换成一个十进制表示,再把转换结果换回一个二进制表示,这个表示能和最早这个二进制表示是一样的。 以上说的是一般的情况。实际上针对上面说的这种转换,已经有算法可以实现对任意浮点数做这种“无损”的转换了。但是这个转换有一些缺点: 1. 比较晚才发现了这样的算法。这个看似简单的问题对人类的大脑来说还是比较复杂, 2. 换出来的十进制表示基本上都很长, 3. 性能不太好。 因此一般显示的浮点数,虽然是有办法精确表示的,但是出于实用的目的一般选择不精确表示。 这就是为什么 c 和 b 不一样,但打印的结果是一样的。 所以如果你需要表示整数,那就要特意的取整。不知道这么说解释清楚没有。 |
9
wenjuncool 2015-01-21 18:13:22 +08:00
学艺不精了吧,浮点数本来就不精确
|
10
tabris17 2015-01-21 18:14:05 +08:00
|
11
revlis7 2015-01-21 18:14:33 +08:00
|
12
66beta 2015-01-21 18:16:19 +08:00
官网手册的示例
<?php echo round(3.4); // 3 echo round(3.5); // 4 echo round(3.6); // 4 echo round(3.6, 0); // 4 echo round(1.95583, 2); // 1.96 echo round(1241757, -3); // 1242000 echo round(5.045, 2); // 5.05 echo round(5.055, 2); // 5.06 ?> |
13
ooh 2015-01-21 18:20:43 +08:00
我想楼主你要没想明白的是这个://(int)('0.57' * 100)=56//
|
14
laoyuan OP 我大概明白这个问题了,int 和 float 进行比较时,把 int 转为 float 值再比较,而 round() 返回的 float 值恰恰是其对应的整数的浮点值,所以 round() 尽管是 float,但和 int 比较时总是相等的。
|
15
FrankFang128 2015-01-21 18:39:55 +08:00 via Android
浮点数就不要比较是否相等了
|
16
laoyuan OP @FrankFang128 不,就用 round 比较,生产环境都是这么做的
|
17
tabris17 2015-01-21 18:43:41 +08:00 1
其实这个问题是:为什么 round() 返回一个 float,但和 int 比较时总是相等的,别的 float 却没有这个技能
=============== <?php var_dump(57.0 == 57, 0.57*100 == 57.0); 怎么就别的float没这个技能了 |
19
qwlhappy 2015-01-21 18:57:00 +08:00
其实应该是var_dump的锅
|
21
mcfog 2015-01-21 19:00:46 +08:00 1
简单来说
永远不要用`==` 无论是JS还是PHP 毕竟他们都是世界上最好的语言 |
23
Delbert 2015-01-21 19:08:33 +08:00
我试了一下
$a = 5.7; $b = 0.57 * 10; $c = round(0.57 * 10, 1); var_dump( $a, $b, $c, $a == $b, $a === $b, $a == $c, $a === $c); 结果是: float(5.7) float(5.7) float(5.7) bool(false) bool(false) bool(true) bool(true) 没想明白ing... |
25
laoyuan OP @Delbert
5.7 和 round(0.57 * 10, 1) 是一个数,都是5.7对应的 float 值,而0.57 * 10 这种对 float 进行运算得到的 float,就是一个不可预知的数了,总之 float 的运算很神奇 |
26
bombless 2015-01-21 19:27:02 +08:00
噗,我24楼看错了,不好意思。
如果真的需要比较浮点数,一般是确定一个可容忍的精度,然后根据这个精度比较两个浮点数的差。 如果可能的话最好就比较整数,像云风的ejoy游戏引擎为了避开这个问题就把所有的数乘以1024,这样以一定损失为代价,全部都进行整数的比较。 货币的话常常就直接用十进制表示,不用浮点数了。 |
27
jevonszmx 2015-01-21 19:37:36 +08:00
http://docs.php.net/manual/zh/language.types.float.php
php官方文档红字警告: 浮点数的精度 浮点数的精度有限。尽管取决于系统,PHP 通常使用 IEEE 754 双精度格式,则由于取整而导致的最大相对误差为 1.11e-16。非基本数学运算可能会给出更大误差,并且要考虑到进行复合运算时的误差传递。 此外,以十进制能够精确表示的有理数如 0.1 或 0.7,无论有多少尾数都不能被内部所使用的二进制精确表示,因此不能在不丢失一点点精度的情况下转换为二进制的格式。这就会造成混乱的结果:例如,floor((0.1+0.7)*10) 通常会返回 7 而不是预期中的 8,因为该结果内部的表示其实是类似 7.9999999999999991118...。 所以永远不要相信浮点数结果精确到了最后一位,也永远不要比较两个浮点数是否相等。 |
28
picasso250 2015-01-21 20:02:18 +08:00
看到楼主这样的语言使用者我就明白为什么PHP是世界上最好的语言了
|
29
endrollex 2015-01-21 20:40:04 +08:00
除非你能搞清这个底层是怎么实现的,是不是bitwise comparison,否则返回什么都没错,浮点根本不能用 ==
|
31
laoyuan OP @picasso250
7年PHP经验不是吹的! |
33
ioth 2015-01-22 15:12:19 +08:00
一半语言无所谓,一半比较说不同,不让比较的除外。
|
34
ryd994 2015-01-22 15:15:00 +08:00 1
正常写程序都是不能直接比较浮点的,要比较的话都是 abs(a-b)<某个精确度
即使是round的结果,如果是浮点数,也无法保证今后就是相等的 这在任何语言里都是,大多数编程教学里也一定会讲到这一点,你写了7年程序还不知道…… 生产环境里比较round结果……呵呵…… PHP是世界上最好的语言,可见一斑 |
36
ryd994 2015-01-22 15:38:14 +08:00
@laoyuan 字符串…………
假如我的需要精确到小数点后10位 比较abs(a-b)<c只需要一次减法,一次abs,一次浮点比较 比较字符串,且不说round和转换的开销,需要整数比较10次(字符就是整数),性能根本没法比 当然,鉴于是PHP,性能就呵呵无所谓了 |
37
xwsoul 2015-01-24 23:47:59 +08:00
为何浮点的梗还在说...这样欺负PHP真的好么? T__T
|
39
xwsoul 2015-01-25 22:57:10 +08:00
|
40
huson 2015-02-08 18:51:31 +08:00 1
楼主 没仔细看手册呀,float 那章有解释的
|
42
huson 2015-02-08 19:20:03 +08:00
@laoyuan
http://php.net/manual/en/language.types.float.php#warn.float-precision 这页有讲 栗子在下面 $x = 8 - 6.4; // which is equal to 1.6 $y = 1.6; var_dump($x == $y); // is not true PHP thinks that 1.6 (coming from a difference) is not equal to 1.6. To make it work, use round() var_dump(round($x, 2) == round($y, 2)); // this is true This happens probably because $x is not really 1.6, but 1.599999.. and var_dump shows it to you as being 1.6. |