分类 "计算机基础" 下的文章

注:本文包含AI创作。

第一部分:浮点数的基础

一、定义与原理

浮点数是计算机科学中用于近似表示实数的一种方法。它们对于处理广泛的值特别有用,特别是在数值的大小超出整数所能表示的范围时。

  1. 表示实数:在现实世界中,许多量(如温度、距离或速度)可以是任意精度的实数。浮点数允许计算机以有限的数字位来近似这些数值。
  2. 构成:一个浮点数由三个部分组成:符号位(表明正负)、指数位(决定数值的规模或大小)和尾数位(提供实际数值的精确度)。
  3. 动态范围:通过分离数值的大小(指数)和精确度(尾数),浮点数能够覆盖非常大的范围,从非常小的数到非常大的数。

二、浮点数的内部表示(IEEE 754标准)

IEEE 754标准是一种广泛采用的标准,用于在计算机中表示浮点数。

  1. 标准格式

    • 单精度(32位):这种格式使用1位符号位、8位指数位和23位尾数位。
    • 双精度(64位):在这种格式中,1位用于符号,11位用于指数,52位用于尾数。
    • 格式:| sign | exponent | fraction |
  2. 符号位:第一位是符号位,0表示正数,1表示负数。
  3. 指数位:指数位用于表示数值的大小。它是一个偏移的二进制表示,这意味着指数的实际值是指数位的值减去一个偏移量。

为什么指数位的值需要偏移量?
比如单精度浮点数,8位指数位可以表达256个数,但只能是非负数。
如果使用+127偏移量(也就是指数3用130表示),负数就可以直接表达,并且可以直接比较大小。

  1. 尾数位:尾数位(或称为有效位)提供了数值的精度。有两种情况:

    • 规约形式:在规约形式中,浮点数被表示为一个非零的数字,这个数字的小数点前有一个非零的数字(通常是1)。这样的表示确保了浮点数的精度和有效位数最大化。
    • 非规约形式:用来表达非常接近0的数字。在这种形式下,浮点数的表示允许尾数的最高位是0,这意味着可以表示比标准规约形式更小的数。

这个地方可能看着很奇怪,它的作用在于对接近 0 的数字提供更高的精度。

比如单精度浮点数 “0.000 ... 00102”,可以表示为 1.02 10^a,也可以表示为 0.000...102 10^b。

如果 a 溢出了,存不了更小的小表达负数(只能存 0,指数位有偏移,没有更小的数了),这个数就表达不了!

但是用 b 表达就可以装进 8 位指数位,也就可以保证精度了。

  1. 特殊值的表示:IEEE 754还定义了一些特殊值的表示方式,如正无穷大(+Infinity)、负无穷大(-Infinity)和非数值(NaN,Not a Number)。

第二部分:使用浮点数时的挑战和注意事项

  1. 精度问题

    • 浮点数由于精度的限制,有时候对计算会有一定的影响。

比如,二进制浮点数不能表达0.1和0.01,0.1的平方既不是准确的0.01,也不是最接近0.01的可表达的数。

浮点数也不能表达圆周率 pi,所以 tan(pi/2) 不等于正无穷,也不会溢出。

  1. 比较与运算

我一般是缩放一定的比例后转换成 int 再比较,GPT4 给了一个新的思路:

package main

import (
    "fmt"
    "math"
)

// FloatEquals 比较两个浮点数是否足够接近,以epsilon作为容差
func FloatEquals(a, b, epsilon float64) bool {
    return math.Abs(a - b) < epsilon
}

func main() {
    a := 0.1
    b := 0.2
    c := 0.3

    // 直接比较 - 往往不可靠
    fmt.Println("Direct comparison:", b+c == a) // false

    // 使用FloatEquals函数比较
    epsilon := 1e-9 // 定义一个足够小的epsilon值
    fmt.Println("Epsilon comparison:", FloatEquals(b+c, a, epsilon)) // true
}
  1. 特殊值的处理(+Inf-InfNaN

    • Go 语言如果你使用浮点数作为 map 的 key,你会发现 map[NaN] != map[NaN]!
    • 因为 NaN != NaN,所以哈希后也是不一致的,底层会加上随机数保证这一特性。
    • 最好不要直接用浮点数当作 key,除非你明确知道数据的形式。
  2. 数值稳定性问题

    • 在连续的运算中,尤其是涉及大量或小量级数值的运算时,精度损失可能会累积。

参考资料: