有关浮点数精度的一个问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
christianwong
V2EX    PHP

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

  •  
  •   christianwong Dec 11, 2013 4468 views
    This topic created in 4523 days ago, the information mentioned may be changed or developed.
    如下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 replies    1970-01-01 08:00:00 +08:00
    bombless
        1
    bombless  
       Dec 11, 2013
    因为一个是单精度浮点数一个是双精度浮点数。
    你把C语言里那个float换成double,就可以看到输出还是57.
    master
        2
    master  
       Dec 11, 2013
    首先需要明白的是浮点数在计算机(二进制)中的存储方式的特殊性。
    另外你用了类型转换,所以这个已经不算存储精度的问题,而是转换策略的问题
    christianwong
        3
    christianwong  
    OP
       Dec 11, 2013
    @master 恩,应该是你说的这个,php不会做相应的优化,而gcc可以
    oldcai
        4
    oldcai  
    PRO
       Dec 11, 2013
    你%d当然是58,%f看看?
    justfindu
        5
    justfindu  
       Dec 11, 2013
    christianwong
        6
    christianwong  
    OP
       Dec 11, 2013
    @bombless 确实换成double就会输出57,原来php中的浮点数都是双精度的
    christianwong
        7
    christianwong  
    OP
       Dec 11, 2013
    @justfindu 确实是看过这个文章之后想起的一个问题
    mille
        8
    mille  
       Dec 11, 2013
    只要把浮点值赋给整形变量,小数点后面的都会被删节
    christianwong
        9
    christianwong  
    OP
       Dec 11, 2013
    @oldcai %f输出的竟然全是0
    oldcai
        10
    oldcai  
    PRO
       Dec 11, 2013
    float a = f*100;

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

    不过在计算机图形这一块,内存到显存的传输消耗很高,存储也很宝贵,甚至有使用双字节长的浮点数的。
    christianwong
        12
    christianwong  
    OP
       Dec 11, 2013
    @oldcai 仍然输出58
    christianwong
        13
    christianwong  
    OP
       Dec 11, 2013
    @bombless 多谢,长见识了
    oldcai
        14
    oldcai  
    PRO
       Dec 11, 2013
    @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  
       Dec 11, 2013
    我觉得是转换策略的问题。
    单精度浮点数的精度大概是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  
       Dec 11, 2013
    @oldcai
    我是在Labwindows测试的,工具比较小众呵呵
    oldcai
        17
    oldcai  
    PRO
       Dec 11, 2013
    你出现的情况实在是比较奇怪,我以为是你没有把int a改成float a
    skydiver
        18
    skydiver  
       Dec 11, 2013
    所以一般都是用 $b = intval(round($a));
    About     Help     Advertise     Blog     API     FAQ     Solana     2698 Online   Highest 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 65ms UTC 14:50 PVG 22:50 LAX 07:50 JFK 10:50
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86