浮点数问题

(1)浮点数是有理数的集合,有些有理数不能表示,会有舍去误差如0.1等。

(2)浮点数可以表示的连续整数也是有限的。

有些脚本语言,比如awk,lua中都是使用浮点数来存储整数的,也就是说,我们在语言中使用的整数,在语言内部是使用浮点数来表示的。我们知道,浮点数的运算中通常存在着一定的误差,所以整数是否能被浮点数精确表示呢?答案是可以,不过不是所有范围的整数都可以被精确的表示。由于浮点数精度的问题,所以浮点数的分布也就呈现出非均匀分布。

先简单介绍一下一个常用的浮点数在计算机中的组成,最常用的浮点数表示法是IEEE754标准,对于这个标准,可以参考[1]

上面就是常用浮点数的表示了,通常sign占用1bit,对于单精度浮点数exponent占用8bits,significand占用23bits。由于IEEE754使用规格化浮点数,所以尾数的最高位必然为1,所以没必要存储,于是有一个隐藏位(hidden bit),所以尾数真正的有效位数为24bits。有兴趣的读者可以参考[1],其中有详细介绍。

当用浮点数来表示整数时,我们要得到连续的整数分布,肯定希望尾数的精度越高越好。很显然,尾数位数有限制,也就限制了能表示的最大的整数的值。对于一个浮点数,设p为其尾数的有效位数(这里p包含一个hidden bit),那么最大的尾数就是1 + 1 - 2^(-p+1),所以最大的整数为(2-2^(-p+1)) * 2^(p-1) = 2^p - 1。由于浮点数是有符号的,所以很自然的我们想到整数范围为[-2^p – 1, 2^p – 1]。可是我们还遗漏了2个数,就是2^p和-2^p。我们来看这两个整数的浮点数表示。规格化后,2^p = (1.0000…000) * 2^p,其中尾数部分小数点后有p个0。但是我们知道,我们的尾数最多只能存储p - 1个,其中一个是hidden bit,但是很巧,由于被舍去的最后一个数字是0,所以不影响实际取值,所以2^p就可以精确表示了。同理-2^p也是如此。

注意,可能有读者会想到,既然1.00..000*2^p可以精确表示,那么很显然,对于单精度浮点数p=24,而指数的可表示范围远大于24,是8-bit,也就是可以到达+127,那么为什么2^p就是可以表示的最大整数呢。因为我们只关心连续的整数范围,2^(p+1)的确可以精确表示,但是[2^p, 2^(p+1)]之间还有许多数就无法表示了,因为尾数不够。

所以对于IEEE754 单精度和双精度浮点数,能够精确表示的整数的范围为

Floating point Range
Single precision [-2^24, 2^24]
Double precision [-2^53, 2^53]

以下代码测试了一下两种浮点数的边界条件(运行环境为VC9):

[cpp] view plaincopyprint?

    1. #include <cassert>
    2. int main()
    3. {
    4. const int max_decimal = 16777216; // 2^24
    5. assert(static_cast<int>(static_cast<float>(max_decimal)) == max_decimal);
    6. assert(static_cast<int>(static_cast<float>(max_decimal + 1)) != max_decimal + 1);
    7. assert(static_cast<int>(static_cast<float>(-max_decimal)) == -max_decimal);
    8. assert(static_cast<int>(static_cast<float>(-max_decimal - 1)) != -max_decimal - 1);
    9. const __int64 max_decimald = 9007199254740992; // 2^53
    10. assert(static_cast<__int64>(static_cast<double>(max_decimald)) == max_decimald);
    11. assert(static_cast<__int64>(static_cast<double>(max_decimald + 1)) != max_decimald + 1);
    12. assert(static_cast<__int64>(static_cast<double>(-max_decimald)) == -max_decimald);
    13. assert(static_cast<__int64>(static_cast<double>(-max_decimald - 1)) != -max_decimald - 1);
    14. }
时间: 2024-10-14 18:27:31

浮点数问题的相关文章

Java中的简单浮点数类型float和double不能够进行精确运算

在java中,简单的浮点类型float和double是不能够进行运算.我们先看下面的两个程序代码: 代码一: import java.util.Scanner; class Circle { double radius; static final double PI=3.14; public Circle(){this.radius=0;} public Circle(double r){this.radius=r;} public double getArea(){return PI*this

单精度浮点数

单精度浮点数格式 是一种计算机数据格式,在计算机存储器中占用4个字节(32 bits),利用"浮点"(浮动小数点)的方法,可以表示一个范围很大的数值. 在 IEEE 754-2008 的定义中,32-bit base 2格式被正式称为binary32格式.这种格式在IEEE 754-1985被定义为single,即单精度. 需要注意的是,在更早的一些计算机系统中,也存在着其他4字节的浮点数格式. 定义 第1位表示正负,中间8位表示指数,后23位表示有效数位. 正负号0代表正,1代表负.

Javascript优化后的加减乘除(解决js浮点数计算bug)

说明 众所周知,js在计算浮点数时候,结果可能会不准确.比如:(在chrome中的运算结果) 2.2 + 2.1 = 4.300000000000001 2.2 - 1.9 = 0.30000000000000027 2.2 * 2.2 = 4.840000000000001 2.1 / 0.3 = 7.000000000000001 网上流传的代码(有bug) 网上流传的优化后的代码如下(有问题的代码,请勿使用) function add(a, b) { var c, d, e; try {

Java 浮点数 float或double类型的表示范围和精度

隐约记得,浮点数判断大小好像有陷阱,因为底层的二进制数不能精确表示所有的小数.有时候会产生让人觉得莫名其妙的事情. 如在java中, 0.99999999f==1f //true 0.9f==1f //false 要明白这些,首先要搞清楚float和double在内存结构 1.内存结构 float和double的范围是由指数的位数来决定的. float的指数位有8位,而double的指数位有11位,分布如下: float: 1bit(符号位) 8bits(指数位) 23bits(尾数位) dou

NOI-1.3-11-计算浮点数相除的余数

11:计算浮点数相除的余数 查看 提交 统计 提问 总时间限制:  1000ms 内存限制:  65536kB 描述 计算两个双精度浮点数a和b的相除的余数,a和b都是正数的.这里余数(r)的定义是:a = k * b + r,其中 k是整数, 0 <= r < b. 输入 输入仅一行,包括两个双精度浮点数a和b. 输出 输出也仅一行,a÷b的余数 样例输入 73.263 0.9973 样例输出 0.4601 提示 注意:输出时小数尾部没有多余的0,可以用下面这种格式:double x;x =

浮点数类型转换的及其内存模型

先看一段测试code: void do_test() { unsigned int uValue = 0xC1480000; printf("uValue = %u,%d,%x,&uValue = %p\n",uValue,uValue,uValue,&uValue); float fValue1 = (float) uValue; printf("fValue1 = %f,&fValue1 = %p, *((unsinged int*)&fV

程序中关于浮点数计算的问题

在进行数值计算编程的过程中往往需要用到浮点数的计算,但浮点数的加减运算通常是会出现误差的.具体出现问题代码如下: double begin = 0.0; //起始位置 double end = 20.0;  //结束位置 int k = 2;  //核函数支持半径的倍数 double initialDis = 0.1;   //粒子间的初始距离(需要与粒子的控制体积保存一致性) /*****************第一步初始化粒子**********/ for(double i=begin-(2

第二章 Java浮点数精确计算

1.实际意义 在实际开发中,如果需要进行float或double的精确计算(尤其是财务计算),直接使用float或double是不行的(具体的例子看下边的代码的main方法的测试结果),需要使用BigDecimal. 2.代码 package com.xxx.util; import java.math.BigDecimal; /** * 浮点数精准算法 */ public class BigDecimalArithUtil { private static final int DIV_SCAL

js实现浮点数保留两位小数代码

js实现浮点数保留两位小数代码:过浮点数小数点后面的数字太长的话,可能需要进行截取操作,下面是一段这样的实例代码和大家分享一下.代码如下: var num=3.1415926; console.log(num.toFixed(2)) 以上代码比较简单,这里就多介绍了,具体可以参阅javascript的Number对象的toFixed()方法一章节. 原文地址是:http://www.softwhy.com/forum.php?mod=viewthread&tid=11735 更多内容可以参阅:h