`
tcspecial
  • 浏览: 897244 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

C/C++ 浮点数存储

阅读更多

 

IEEE浮点数标准定义了两种基本的格式:以4个字节表示单精度格式和8个字节表示双精度。

 

一. 存储规则

float:

1位符号数 8位指数 23位有效数

0/1 bias:127

double:

1位符号数 11位指数 52位有效数

0/1 bias:1023 

 

1.1 8.25存储分析

(8.25)10 = (1000.01)2

 

划分三部分:

1. 符号位: 0                      0正数,1负数

2. 指数位: 10000010        科学记数法表示:(1000.01)2 = 1.00001*2^3,指数为:127+3=130

3. 有效位: 00001 000000000000000000    最高位1去除,不足23位则补0

组合三部分:0 10000010 00001000000000000000000

 

反向推导01000001000001000000000000000000对应十进制值:

0                正数

10000010 130-127=3有效位为3

00001000000000000000000  整数部分补1为:1000      小数部分01 即1000.01

 

1.2 8.58存储分析

来点复杂的,求8.58单精度浮点数存储方式:

十进制小数转化为二进制,不断乘以2,顺次取整数位。

 

0.58*2 = 1.16 1 
0.16*2 = 0.32 0
0.32*2 = 0.64 0
0.64*2 = 1.28 1
0.28*2 = 0.56 0
0.56*2 = 1.12 1
0.12*2 = 0.24 0
0.24*2 = 0.48 0
0.48*2 = 0.96 0
0.96*2 = 1.92 1
0.92*2 = 1.84 1
0.84*2 = 1.68 1
0.68*2 = 1.36 1
0.36*2 = 0.72 0
0.72*2 = 1.44 1
0.44*2 = 0.88 0
0.88*2 = 1.76 1
0.76*2 = 1.52 1
0.52*2 = 1.04 1
0.04*2 = 0.08 0
0.08*2 = 0.16 0
0.16*2 = 0.32 0
0.32*2 = 0.64 0
0.64*2 = 1.28 1
0.28*2 = 0.54 0
0.54*2 = 1.08 1
 

 

通过上面的计算,我们发现0.58自0.16处一直循环,二进制方式不能完整表示该整数,这会有什么影响?

 

8.58 = 1000.10010100011110101110000...

二进制存储方式:

0 10000010 00010010100011110101110

 

测试程序:

float a = 8.58f;
char *p = (char*)&a;

p a
$1 = 8.57999992
p /x *p@4
$2 = {0xae, 0x47, 0x9, 0x41}

 

gdb调试发现a的值怎么变成8.57999992,我们用上述二进制计算其10进制看看:

0.58 = 10010100011110101110000

 

>>> 2**-1+2**-4+2**-6+2**-10+2**-11+2**-12+2**-13+2**-15+2**-17+2**-18+2**-19

0.57999992370605469

 

上述结果与gdb调试一致,除了可以表示为2的幂次以及整数数乘的浮点数可以准确表示外,其余的数的值都是近似值。同时float有效位才23位,导致大部分位数被截断。

 

二. 浮点数大小比较

既然浮点数大多是存储的近似值,那么如何比较其大小?

/**
 * 浮点数大小比较
 */
bool IsEqual(float a, float b, float absError, float relError )  
{  
	// 2的幂次小数,如0.5
    if (a==b) return true;  

    // 绝对误差判断
    if ( fabs(a-b)<absError ) return true;  

    // 相对误差判断
    if ( fabs(a)<fabs(b) )   return (fabs((a-b)/b)<relError ) ? true : false;  
    else return (fabs((a-b)/a)<relError ) ? true : false;  
} 

 

 

三. 硬件支持

为了加快浮点数的运算速度,现处理器大多增加了FPU(Floating-point Unit),用于处理浮点数运算。

可以看下VC++6.0的启动函数:

main()
	mainCRTStartUp()
		_cinit();	// 初始化全局数据和浮点寄存器
		mainret = main( _argc, _argv, _environ );	// 调用main

 

_cinit函数片断:

// 初始化浮点寄存器
if( _FPinit != NULL )
	(*_FPinit)();

 

四. 面试题

如何求取两数相除的商,不能用* / %操作符?

 

题目不能用* % /操作,那只能用位操作了,将除法变成减法。

算法原理:让除数左移使得除数扩大接近被除数,直到除数增大有余数存在,然后让被除数减去这个增大后的除数,让余数去进行判断。 

#define INT_MAX 0x7fffffff
#define INT_MIN (-0x7fffffff-1)

/**
 * 两数相除
 */
int divide(int dividend, int divisor) {
	// 0
    if( divisor == 0 )
    	return INT_MAX;

    bool isNeg = (dividend^divisor) >> 31 == 1;
    int result = 0;

    // min
    if( dividend == INT_MIN )
    {
    	dividend += abs(divisor);
    	if( divisor == -1 )
    	{
    		return INT_MAX;
    	}	

    	result++;
    }

    // min
    if( divisor == INT_MIN )
    	return result;

    ///
    dividend = abs( dividend );
    divisor = abs( divisor );
    int digit = 0;

    // 增大除数的倍数至与除数接近
    while( divisor <= (dividend>>1) )
    {
    	divisor <<= 1;	// *2
    	digit++;	// bit
    }

    while( digit >= 0 )
    {
    	// 余数
    	if( dividend >= divisor )
    	{
    		result += 1<<digit;	// 倍数
    		dividend -= divisor; // 差值
    	}

    	// 减少除数的倍数
    	divisor >>= 1;
    	digit--;
    }

    return isNeg? -result:result;
}

 

 

 

参考链接:

十进制转化为二进制小数

浅谈C/C++的浮点数在内存中的存储方式

 

 

 

 

 

 

分享到:
评论

相关推荐

    深入C/C++浮点数在内存中的存储方式详解

    本篇文章是对C/C++浮点数在内存中的存储方式进行了详细的分析介绍,需要的朋友参考下

    C/C++的浮点数在内存中的存储方式分析及实例

    主要介绍了C/C++的浮点数在内存中的存储方式分析及实例的相关资料,需要的朋友可以参考下

    浮点数与十六进制转换工具

    在 C/C++中,使用浮点方式存储实数,用两种数据类型来保存浮点数: foat(单精度)和double(双精度)。float在内存中占4字节,double在内存中占8字节。由于占用空间大,double可描述的精度更高。这两种数据类型在内存中...

    opencv3/C++实现光流点追踪

    InputArray prevPts, //二维点向量存储找到的光流;点坐标必须是单精度浮点数 InputOutputArray nextPts,//输出二维点向量(用单精度浮点坐标)包括第二幅图像中计算的输入特征的新点位置;当OPT

    基于C++浮点数(float、double)类型数据比较与转换的详解

    浮点数在内存中的存储机制和整型数不同,其有舍入误差,在计算机中用近似表示任意某个实数。具体的说,这个实数由一个整数或定点数(即尾数)乘以某个基数(计算机中通常是2)的整数次幂得到,这种表示方法类似于...

    C语言难点分析整理

    12. 浮点数的存储格式: 50 13. 位域 58 14. C语言函数二维数组传递方法 64 15. C语言复杂表达式的执行步骤 66 16. C语言字符串函数大全 68 17. C语言宏定义技巧 89 18. C语言实现动态数组 100 19. C语言笔试-运算符...

    免费下载:C语言难点分析整理.doc

    12. 浮点数的存储格式: 50 13. 位域 58 14. C语言函数二维数组传递方法 64 15. C语言复杂表达式的执行步骤 66 16. C语言字符串函数大全 68 17. C语言宏定义技巧 89 18. C语言实现动态数组 100 19. C语言笔试-运算符...

    c语言难点分析整理,C语言

    12. 浮点数的存储格式: 50 13. 位域 58 14. C语言函数二维数组传递方法 64 15. C语言复杂表达式的执行步骤 66 16. C语言字符串函数大全 68 17. C语言宏定义技巧 89 18. C语言实现动态数组 100 19. C语言笔试-运算符...

    高级C语言 C 语言编程要点

    12. 浮点数的存储格式: 50 13. 位域 58 14. C语言函数二维数组传递方法 64 15. C语言复杂表达式的执行步骤 66 16. C语言字符串函数大全 68 17. C语言宏定义技巧 89 18. C语言实现动态数组 100 19. C语言笔试-运算符...

    史上最强的C语言资料

    12. 浮点数的存储格式: 50 13. 位域 58 14. C语言函数二维数组传递方法 64 15. C语言复杂表达式的执行步骤 66 16. C语言字符串函数大全 68 17. C语言宏定义技巧 89 18. C语言实现动态数组 100 19. C语言笔试-运算符...

    高级C语言详解

    12. 浮点数的存储格式: 50 13. 位域 58 14. C语言函数二维数组传递方法 64 15. C语言复杂表达式的执行步骤 66 16. C语言字符串函数大全 68 17. C语言宏定义技巧 89 18. C语言实现动态数组 100 19. C语言笔试-运算符...

    C语言难点分析整理.doc

    12. 浮点数的存储格式: 50 13. 位域 58 14. C语言函数二维数组传递方法 64 15. C语言复杂表达式的执行步骤 66 16. C语言字符串函数大全 68 17. C语言宏定义技巧 89 18. C语言实现动态数组 100 19. C语言笔试...

    高级进阶c语言教程..doc

    12. 浮点数的存储格式: 50 13. 位域 58 14. C语言函数二维数组传递方法 64 15. C语言复杂表达式的执行步骤 66 16. C语言字符串函数大全 68 17. C语言宏定义技巧 89 18. C语言实现动态数组 100 19. C语言笔试-运算符...

    单双精度浮点数解析.c

    对于计算机中常见的浮点数存储格式进行分析,编程提取float和double中的阶码好尾码。

    11076浮点数的分数表达

    在计算机中,用float或double来存储小数有时不能得到精确值,若要精确表达一个浮点数的计算结果, 最好用分数来表示小数,有限小数或无限循环小数都可以转化为分数,无限循环小数的循环节用括号标记出来。如: 0.9 =...

    嵌入式系统/ARM技术中的如何处理ARM体系下浮点数Middle-Endian问题

     由于可移植性好,相当一部分嵌入式软件都是用C/C++语言开发的,而C/C++语言编写的程序中数据存储字节顺序是与编译平台所用的CPU相关的,所以嵌入式软件移植过程中,数据存储字节顺序是需要重点处理的地方。...

    11076 浮点数的分数表达

    在计算机中,用float或double来存储小数有时不能得到精确值,若要精确表达一个浮点数的计算结果, 最好用分数来表示小数,有限小数或无限循环小数都可以转化为分数,无限循环小数的循环节用括号标记出来。如: 0.9 =...

Global site tag (gtag.js) - Google Analytics