V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
christianwong
V2EX  ›  PHP

有关浮点数精度的一个问题

  •  
  •   christianwong · 2013-12-11 10:46:44 +08:00 · 3885 次点击
    这是一个创建于 4004 天前的主题,其中的信息可能已经有所发展或是发生改变。
    如下php代码:

    $f = 0.58;
    print_r(intval($f*100));

    输出57,


    如下C语言代码:
    #include <stdio.h>

    int main()
    {
    float f = 0.58;

    int a = f*100;

    printf("%d\r\n", a);

    return 0;
    }

    输出58.


    这是系统问题,还是语言问题?
    不同的语言对浮点数的策略还不一样?
    18 条回复    1970-01-01 08:00:00 +08:00
    bombless
        1
    bombless  
       2013-12-11 10:57:55 +08:00
    因为一个是单精度浮点数一个是双精度浮点数。
    你把C语言里那个float换成double,就可以看到输出还是57.
    master
        2
    master  
       2013-12-11 11:03:26 +08:00
    首先需要明白的是浮点数在计算机(二进制)中的存储方式的特殊性。
    另外你用了类型转换,所以这个已经不算存储精度的问题,而是转换策略的问题
    christianwong
        3
    christianwong  
    OP
       2013-12-11 11:09:07 +08:00
    @master 恩,应该是你说的这个,php不会做相应的优化,而gcc可以
    oldcai
        4
    oldcai  
       2013-12-11 11:10:22 +08:00
    你%d当然是58,%f看看?
    justfindu
        5
    justfindu  
       2013-12-11 11:11:24 +08:00
    christianwong
        6
    christianwong  
    OP
       2013-12-11 11:11:27 +08:00
    @bombless 确实换成double就会输出57,原来php中的浮点数都是双精度的
    christianwong
        7
    christianwong  
    OP
       2013-12-11 11:11:48 +08:00
    @justfindu 确实是看过这个文章之后想起的一个问题
    mille
        8
    mille  
       2013-12-11 11:11:49 +08:00
    只要把浮点值赋给整形变量,小数点后面的都会被删节
    christianwong
        9
    christianwong  
    OP
       2013-12-11 11:12:52 +08:00
    @oldcai %f输出的竟然全是0
    oldcai
        10
    oldcai  
       2013-12-11 11:14:29 +08:00
    float a = f*100;

    printf("%f\r\n", a);
    bombless
        11
    bombless  
       2013-12-11 11:17:51 +08:00
    如果不是出于存储或者网络传输的目的,单精度浮点数根本没有什么用。
    所以多数编程语言根本就没有单精度浮点数只有双精度浮点数。

    不过在计算机图形这一块,内存到显存的传输消耗很高,存储也很宝贵,甚至有使用双字节长的浮点数的。
    christianwong
        12
    christianwong  
    OP
       2013-12-11 11:46:33 +08:00
    @oldcai 仍然输出58
    christianwong
        13
    christianwong  
    OP
       2013-12-11 11:46:46 +08:00
    @bombless 多谢,长见识了
    oldcai
        14
    oldcai  
       2013-12-11 13:03:13 +08:00
    @christianwong 已测试,输出58.000000,你看看是不是哪里出问题了。
    prove.c:

    #include<stdio.h>

    int main(void)
    {
    float f = 0.58;
    float a = f*100;
    printf("%f\r\n", a);
    return 0;
    }

    gcc -Wall prove.c -o prove
    jiji9081
        15
    jiji9081  
       2013-12-11 16:52:22 +08:00
    我觉得是转换策略的问题。
    单精度浮点数的精度大概是6~7位有效数字,对付这种情况绰绰有余。
    float f = 0.58;
    a = f*100.0;
    得到结果是57
    但是
    float f = 0.58;
    f = f * 100;
    a = f;
    结果是58

    事实上,在float f = 0.58这里已经存在有误差,实际保存的值换算成10进制是0.5799999237060547
    那么×100后得到的就是57.99999237....这样的
    两种策略一种是扔掉小数点,一种是舍入为最接近值

    @oldcai
    jiji9081
        16
    jiji9081  
       2013-12-11 16:59:13 +08:00
    @oldcai
    我是在Labwindows测试的,工具比较小众呵呵
    oldcai
        17
    oldcai  
       2013-12-11 17:12:34 +08:00
    你出现的情况实在是比较奇怪,我以为是你没有把int a改成float a
    skydiver
        18
    skydiver  
       2013-12-11 17:31:55 +08:00
    所以一般都是用 $b = intval(round($a));
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1394 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 21ms · UTC 17:32 · PVG 01:32 · LAX 09:32 · JFK 12:32
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.