Board logo

标题: MySQl的float问题汇总 [打印本页]

作者: fangzhen    时间: 2010-1-5 09:11     标题: MySQl的float问题汇总

发现了一个比较奇特的问题!

表结构如下:
CREATE TABLE `test` (
`id` int(10) unsigned NOT NULL auto_increment,
`user_id` int(10) unsigned NOT NULL default '0',
   `result` float NOT NULL default '0',
`times` int(10) unsigned NOT NULL default '0',
PRIMARY KEY (`id`))
记录如下
1,123,2.01,...
2,888,2.52,...
.......

执行select * from test where result=2.52
结果为空集;
再执行select * from test where result="2.52"
还是空集

假设table中有一个price=28.8的记录(price为float型),那么你用
Sql代码 复制代码

   1. select * from table where price=28.8
是有可能select不到这条记录的,因为10进制和2进制之间的误差,这个28.8有可能是28.7999999
到目前为止我想到是有两个方案:
一个是这样select(其实在对精准要求比较高的情况下,这样可能是有问题)
   select * from table where price>28.7 and price<28.9

2.还有一个是在设计的时候比较fancy的解决方案(号称google是这样搞的):

根本不设计float型的字段,而是用一个int型+标识这个int型的小数位来代替float型,也就是price=28.8在数据库中存的是price=288,precision=1

但是
以上方法有缺陷,第一个方法大多用户估计行不通,精度不一样。不太好控制
第二个方法设计确实比较有技巧,但是无法在MySQL中简单的进行排序。
而我的需求即是又要能排序,又要可以使用where result=2.52
我想了第三种方法,就是再增加一个字段
执行alter table test add cresult varchar(32) not null;即可
这样当我要执行排序操作时
select * from test order by result desc;
执行开头那个例子时
select * from test where cresult="2.52"
二个字段分工不同。

当然我也想到了第四种方法,但适用范围小,是有前提的
即result里面的值必须固定长度
比如22.98,即小数点前和小数点后都必须为n位数,也就是说范围从00.00-99.99
或者000.000-999.999
第一类00.00-99.99以小数点为分隔,看此小数看成100进制,假设数为12.23,那么12*(100的1次方)+23*(100的0次方),结果为一整型
第二类同理,看成1000进制。
当需要知道真实值时把100或1000进制转换一下即可得到原始值。
这样把转换后的值存入result里(此时result为int型),即可排序又可where result=计算后的值
作者: fangzhen    时间: 2010-1-5 09:13

现象: 在判断语句里,两组显示相同数据的php变量不相等,这两组变量取直mysql float类型变量。
比如:$a-$b != $c
$a,$b,$c都取值mysql的float变量。
如果echo $a-$b;echo $c;的话发现它们是相同的,但是if($a-$b != $c)判断中它是ture的。
于是我想办法测试:
1)找出它们的php变量类型,gettype()函数显示它们都是tring。
2)把它们用doubleval()都转换为double类型,判断还是ture。
3)自己想了个办法:每个变量*100然后用intval()函数去掉尾巴(注 这些变量都是两位的,在mysql里是float(10,2))比较发现还是ture,echo它们的值,发现有变化,有些比mysql里面的值小,奇怪了!

这是编程的一个经典问题,尤其是float变量之间的大小比较。

比较两个float变量a,b是否相等,不能用
if (a == b)

而要用
if ( (a-b) < 0.001 || (b-a) < 0.001 )

0.001是一个预设的小常量,取决与你要的精度。如要测不等,换成大于号(>)。

之所以如此,是因为计算机用的是二进制,不能无限制地记录一个数字的精度。而且在二进制(机器用)和十进制之间转换时,又有精度损失。经常是你看到的两个十进制数字是一样时,其实它们在机器中存储的二进制数值略有不同。比较时机器用二进制一比,就发现不等,而人一看十进制却以为相等。




欢迎光临 PHP开发笔记 (http://phpvi.com/) Powered by Discuz! 6.1.0