ITPub博客

首页 > 数据库 > PostgreSQL > PostgreSQL 源码解读(196)- 浮点数比较

PostgreSQL 源码解读(196)- 浮点数比较

原创 PostgreSQL 作者:husthxd 时间:2019-05-23 16:39:33 0 删除 编辑

众所周知,计算机是以二进制方式存储数据,而浮点数在序列化为二进制时可能会出现精度丢失(IEEE 754标准),对于数据库实现来说,会引入一个问题,那就是那么两个浮点数之间在比较时在数据库是如何实现的?
下面是用于测试脚本:


testdb=# select 123.31::double precision > 123.45::double precision;;

一、数据结构

浮点数的编码可参考维基百科,简单来说由三部分组成,包括符号位,有效数字和指数位.其中,在指数位全为1(二进制的1)时,如果有效数字不全为0,那么这个数不是一个数(以nan表示).

二、源码解读

浮点数(双精度)的比较实现函数是float8_cmp_internal,逻辑比较简单.
其中nan亦即上面介绍的”不是一个数nan”


/*
 *      float8{eq,ne,lt,le,gt,ge}       - float8/float8 comparison operations
 */
int
float8_cmp_internal(float8 a, float8 b)
{
    /*
     * We consider all NANs to be equal and larger than any non-NAN. This is
     * somewhat arbitrary; the important thing is to have a consistent sort
     * order.
     */
    if (isnan(a))
    {
        if (isnan(b))
            return 0;           /* NAN = NAN */
        else
            return 1;           /* NAN > non-NAN */
    }
    else if (isnan(b))
    {
        return -1;              /* non-NAN < NAN */
    }
    else
    {
        if (a > b)//a > b,返回1
            return 1;
        else if (a < b)//a < b,返回-1
            return -1;
        else
            return 0;//否则,返回0
    }
}

在C语言中,浮点数不要比较相等或不等,但可以进行<,>,>=,<=运算.
但在SQL中,可以进行相等或不等运算,因为实质通过>, <进行比较的实现而不是浮点数的直接等值比较实现.

三、跟踪分析

测试脚本


testdb=# select 123.31::double precision > 123.45::double precision;

跟踪分析


(gdb) c
Continuing.
Breakpoint 1, float8_cmp_internal (a=123.31, b=123.45) at float.c:1056
1056        if (isnan(a))

查看内存中的数据(8个字节,以单字节b方式显示)


(gdb) x/8b &a
0x7ffcd2cac728: 0xa4    0x70    0x3d    0x0a    0xd7    0xd3    0x5e    0x40
(gdb) x/8b &b
0x7ffcd2cac720: 0xcd    0xcc    0xcc    0xcc    0xcc    0xdc    0x5e    0x40
(gdb)

同时,我们用c语言来打印123.31和123.45的二进制编码作为对照


[xdb@localhost source]$ cat double_test.c 
#include <stdio.h>
int main() {
    double d1 = 123.31;
    double d2 = 123.45; 
    printf("d1 : %llx \n", *((long *)&d1)); 
    printf("d2 : %llx \n", *((long *)&d2)); 
}
[xdb@localhost source]$ gcc double_test.c -o dt
[xdb@localhost source]$ ./dt 
d1 : 405ed3d70a3d70a4 
d2 : 405edccccccccccd

输出的值与在跟踪分析中的内存值一致.

DONE!

四、参考资料

PG数据类型
浮点数的二进制表示

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/6906/viewspace-2645320/,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
长期从事政务、金融等行业产品研发和架构设计工作,ITPUB数据库版块资深版主,对Oracle、PostgreSQL有深入研究。现就职于广州云图数据技术有限公司,系统架构师。

注册时间:2007-12-28

  • 博文量
    1274
  • 访问量
    3749847