zoukankan      html  css  js  c++  java
  • 代码之谜(四) 浮点数(从惊讶到思考)

    在『代码之谜』系列的前几篇文章中,很多次出现了浮点数。 浮点数在很多编程语言中被称为简单数据类型,其实,浮点数比起那些复杂数据类型(比如字符串)来说, 一点都不简单。

    单单是说明 IEEE浮点数 就可以写一本书了,我将用几篇博文来简单的说说我所理解的浮点数,算是抛砖引玉吧。

    一次面试

    记得多年前我招聘 Java 程序员时的一次关于浮点数、二分法、编码的面试, 多年以后,他已经称为了一名很出色的程序员。 每次聚会他都会告诉我,“那次面试彻底改变了我的过去的学习方式, 我以前 只是盲目接受知识,根本就没有自己思考过, 那次对话,比我大学四年学到的知识都多”。

    我看他简历上写到读过《信息论》才谈了很多关于二分法以及编码的话题, 整个过程大概3个小时——这是我面试时间最长的一次。

    因为时间久远,我把一些我能回忆起来的关于浮点数的内容整理在这篇博客中。

    格式说明:

    所有我说的话,都放在引用里面。他的话放在了引号(“”)里面。没有加引号的是我的心理活动或者说明。

    浮点数个数

    在 8 位计算机上,浮点数一共有多少个呢?

    “8 位的好像太过时了,现在主流的是 32 位的,好像可以表示3 x 10^38。”

    果然不出我所料, 很多毕业生都把计算机学成了文科,他们不是在学习理论知识,而是接受/背诵这些知识

    8 位计算机可以表示的整数是多少个呢?

    “这个简单,2的8次方,应该是 256 个。N 位计算机表示的整数就是 2 的 N 次方。”

    他回答时显得很兴奋,因为他终于可以反驳我的观点了,他没有把计算机当作死记硬背的学科。

    8 位计算机,或者说 8bit 可以表示 2^8 个整数。 如果用这 8bit 来表示字符,可以表示多少个呢?

    “呵呵,当然也是 2 的 8 次方了,否则就没有必要再发明16位或者32位的 unicode 去表示汉字了。”

    如你刚才所说,8bit 可以表示 3^38 个浮点数。那么你估算一下,2bit 可以表示多少个浮点数呢?

    “既然 2bit 可以表示 4 个整数,浮点数嘛肯定比这个多,最少也得能表示 10 几个浮点数吧。”

    好吧,按照你的思路,我说几个数。

    • 0总该有吧,用 00 表示。
    • 1 用 01 表示
    • 2 用 10 表示
    • 3 用 11 表示

    现在你把 0.4 给我表示出来?

    『他思索了片刻』“哦。我明白了, 2bit 可以表示 4 个数,不管是整数、小数或者字符,就算是用 2bit 表示苹果,我们也只能表示 4 个,如果想要表示更多,就得用更多的 bit 位。”

    虽然他在简历中写到读过《信息论》,他对 N bit可以表示的信息量是 2^N 肯定没有完全理解,或者只是被动接受了这个定理。

    过了一会儿他又继续说:“按照这个逻辑,8bit 只能表示 256 个浮点数了,这也太少了。 我有点糊涂了,浮点数的表示范围一般都得几万甚至几亿啊。”

    浮点数精度

    于是我在 firebug 里面写了几行代码(可以在本系列第一篇的 序言 部分找到这些代码)。

    0.2 + 0.4
    
    0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1

    “这怎么可能呢?JS 居然这么不严格?”

    显然他把这种现象归结于 js(谢天谢地,他没有把罪过加在 firebug 身上)。 于是我用 Java 重写了上面的代码,这回他只剩目瞪口呆了。

    既然他已经开始 惊讶,那么下一步就是 思考。我又稍作了解释:

    任何语言都宣称他们的浮点数的表示范围是 3 x 10^38,这个数到底多大呢?目前所知宇宙的年龄是 1.373 x 10^10 年。

    但是 32bit 最多只能表示 2^32 个数,大约是 4 x 10^9。

    对比一下你就会发现令人震惊的结果。 如果把浮点数的范围比做地球,那么可以精确表示的浮点数还不到一粒芝麻大。

    “这么说,0.2+0.4 是因为他不能够精确表示,所以出现了计算错误的现象。那在编程中如何避免这种问题呢?”

    用 定点数表示小数

    浮点数等价于小数吗

    “定点数不是整数吗?定点数怎么表示小数啊?”

    很显然,有一个理论性概念错误。他没有真正理解什么是定点,什么是浮点。

    浮点数可以表示整数吗?比如,float a = 2 可以吗?

    “可以是可以,这个 2 在计算机里面应该存储的是 2.0 吧?”

    计算机肯定没有存储 2.0。百分之一万的肯定。计算机存储的是0、1串。呵呵。

    “我觉得浮点数应该不会存储整数的2,他存储的应该是小数的2.0,然后转换成0、1串,是这样吗?”

    他一连问了我几个问题,使我感觉到,我不是在面试,而是在上课。

    整数和小数是数学里面的概念,在计算机中,只有定点数和浮点数,没有整数和小数

    定点数在课本里如何定义的?

    “忘了,只知道定点数就是整数,浮点数就是小数。好像老师也是这么讲的。”

    那是因为你们老师不是我,如果我当老师,肯定不会这么教学生。『笑』

    定点、浮点,“点”是什么意思?“点”就是小数点。 把小数点固定,通常固定在最右面,就是定点数。 把小数点浮动,就是浮点数。浮点在哪儿?这个在 IEEE 浮点数标准里面定义的。

    回到前面话题,如何精确的表示小数呢?其中一种方案就是定点数。

    拿 8bit 举例吧。我们可以把小数点定在中间,用 4bit 表示整数部分,4bit 表示小数部分。 这样构造方式(专业点我们称他为数据结构,一般语言把整数和小数称为简单数据类型,其实他们一点都不简单,而且比那些成了复合数据类型的字符串都要复杂的多),我们可以精确的表示256个小数。


    在下一章,我们将构造一个 8bit 的浮点数表示形式,来深入探索浮点数不为人知的秘密。 我称它为 JJFN-134(JustJavac Float Notation,justjavac浮点数表示法),1bit符号,3bit指数,4bit尾数。

  • 相关阅读:
    771. Jewels and Stones
    706. Design HashMap
    811. Subdomain Visit Count
    733. Flood Fill
    117. Populating Next Right Pointers in Each Node II
    250. Count Univalue Subtrees
    94. Binary Tree Inorder Traversal
    116. Populating Next Right Pointers in Each Node
    285. Inorder Successor in BST
    292. Nim Game Java Solutin
  • 原文地址:https://www.cnblogs.com/lanzhi/p/6468259.html
Copyright © 2011-2022 走看看