V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
ryanking8215
V2EX  ›  Python

python3 float 精度问题

  •  
  •   ryanking8215 ·
    ryanking8215 · 2016-02-02 16:49:51 +08:00 · 6592 次点击
    这是一个创建于 3251 天前的主题,其中的信息可能已经有所发展或是发生改变。

    在 x86 上,a = 1.1, 打印 a 还是 1.1
    但是在 arm 平台上,a=1.1, 打印 a 是1.1000000001字样。

    最后协议通过 json 格式发送,协议要求是.1f 的格式。 json 序列化通过标准库里的,然后就整不出来了。

    请教一下大家,怎么解决, 谢谢。

    第 1 条附言  ·  2016-02-04 14:39:38 +08:00
    已解决,通过指定” ac_cv_little_endian_double=yes “使 floatobject 的 repr 使用 short 方式,否则使用 legacy 方式。
    13 条回复    2016-02-04 14:38:09 +08:00
    P0P
        1
    P0P  
       2016-02-02 17:05:16 +08:00
    最后转换成字符串喽。。。 `a = '0.1f' % a`
    ryanking8215
        2
    ryanking8215  
    OP
       2016-02-02 17:07:18 +08:00
    @lazydomino 转换成字符串是可以的,但是 json 序列化后是 string 了,不是 number 了。
    P0P
        3
    P0P  
       2016-02-02 17:18:56 +08:00   ❤️ 1
    网上说是因为某些 arm 芯片没有 hardware float module 的原因,需要特别编译版本的 python
    neoblackcap
        4
    neoblackcap  
       2016-02-02 17:19:35 +08:00
    这个其实不算是 Python 的问题,所有浮点都是这样的,因为二进制不能精确表示所有小数。

    你可以选择 decimal.Decimal 来替代 float ,在 json.load 里面启用 parse_float 参数就可以了

    甚至你可以传入一个你自己定义的 JSONEncoder 子类来实现你想要的效果
    neoblackcap
        5
    neoblackcap  
       2016-02-02 17:20:42 +08:00
    补充一下,是 json.loads ,当然 parse_float 这个形参在 json.load 里面也是支持的
    lhbc
        6
    lhbc  
       2016-02-02 17:22:22 +08:00
    $ uname -a
    Linux RaspberryPi 4.1.17-1-ARCH #1 SMP Mon Feb 1 18:55:49 MST 2016 armv7l GNU/Linux

    $ python
    Python 3.5.1 (default, Dec 11 2015, 05:35:45)
    [GCC 5.3.0] on linux
    >>> a = 1.1
    >>> print(a)
    1.1
    zhicheng
        7
    zhicheng  
       2016-02-02 17:47:56 +08:00
    用 decimal 。
    ryanking8215
        8
    ryanking8215  
    OP
       2016-02-02 17:50:33 +08:00
    @lhbc 请教一下交叉编译的方法,有没有特殊的做法?我的交叉编译器是 gcc 4.4.1, 也是 armv7l 的
    lhbc
        9
    lhbc  
       2016-02-02 18:10:38 +08:00
    @ryanking8215 我是直接用 Archlinux, 自带 Python 3.5.1
    proudzhu
        10
    proudzhu  
       2016-02-02 18:30:30 +08:00 via Android
    为啥不直接传 * 10 之后的整形数据
    fy
        11
    fy  
       2016-02-02 22:00:58 +08:00
    要高精度,你需要 decimal 特别是处理钱
    ryanking8215
        12
    ryanking8215  
    OP
       2016-02-03 08:48:20 +08:00
    @neoblackcap 谢谢,但我要用的是 json.dumps
    ryanking8215
        13
    ryanking8215  
    OP
       2016-02-04 14:38:09 +08:00
    各位,这个问题解决了,解决方法是在 CONFIG_SITE 里增加'ac_cv_little_endian_double=yes'。

    详情追溯:
    仔细一想,和"精度"没有关系,本来 float 里存的就是那个数据,又没有参与运算, decimal 也解决不了问题,只不过浮点数变量显示的不是我要的格式。于是去"floatobject.c"里碰碰运气,发现它通过一个“ PY_NO_SHORT_FLOAT_REPR ”宏来指定 repr 的方法。

    废话不多说的,关键字: "floatobject.c"->"PY_NO_SHORT_FLOAT_REPR"->"DOUBLE_IS_LITTLE_ENDIAN_IEEE754"->"ac_cv_little_endian_double"

    从 sys.float_repr_style 里也可以得到"short"或者” legacy"的方法,但是改了没用,因为是在编译时确定的。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2548 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 15:20 · PVG 23:20 · LAX 07:20 · JFK 10:20
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.