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++编译器都是采用IEEE所制定的标准浮点格式,即二进制科学表示法。在二进制科学表示法中,S=M*2^N 主要由三部分构成:符号位+阶码(N)+尾数(M)。对于float型数据,其二进制有32位,其中符号位1位,阶码8...
`char`在C/C++中通常被用来表示一个单个字符,但在某些情况下也可用于存储小范围的整数值。 - **Byte (8位无符号整数)** `Byte`是Delphi中的8位无符号整数类型,与C/C++中的`BYTE`或`unsigned char`相对应。注意...
它广泛应用于分布式系统、网络通信和数据存储等领域,尤其是在需要快速处理大量数据的C/C++程序中。Msgpack支持多种编程语言,包括C/C++,使得跨平台的数据交换变得更加便捷。 **C/C++ msgpack库** C/C++中的...
### C/C++ 语句与函数大全解析 #### 概述 C 和 C++ 是两种广泛使用的编程语言,尤其在系统编程、游戏开发、嵌入式系统等领域具有不可替代的地位。掌握这两种语言的关键之一就是熟悉它们提供的各种内置函数。本文将...
C/C++的浮点数在内存中的存储方式分析 任何数据在内存中都是以二进制的形式存储的,例如一个short型数据1156,其二进制表示形式为00000100 10000100。则在Intel CPU架构的系统中,存放方式为 10000100(低地址单元) ...
它与C/C++之间的接口调用允许开发者利用C/C++的高性能计算能力来弥补Lua在性能上的不足,同时也能够使用Lua来简化C/C++代码的开发。要实现Lua与C/C++之间的接口调用,我们需要了解Lua的基础语法,以及如何使用Lua的C...
《C/C++函数库查询字典》是一款专为C/C++开发者设计的工具,它集成了C和C++编程语言中的各种函数库,为程序员提供了一个便捷、高效的查询平台。这款资源尤其适合初学者和经验丰富的开发人员,帮助他们在编写代码时...
ARM架构下C/C++过程调用标准是ARM应用程序二进制接口(ABI)的一个重要组成部分,它规定了函数调用时的参数传递、寄存器使用、堆栈行为以及数据布局等重要约定。这一标准对于开发者编写与硬件紧密相关的软件尤为重要...
对于整数类型的变量,在C/C++中,如果使用两个字节来存储整数,则最大十进制数值为: - 无符号整数 (unsigned): `2^16 - 1 = 65535` - 有符号整数 (signed): `-2^15` 到 `2^15 - 1`,即 `-32768` 到 `32767` 因此,...
### C/C++ 语言参考知识点概述 #### 一、引言 IBM 的 C/C++ 语言参考是一份详尽的文档,旨在为开发者提供全面深入的 C 和 C++ 编程语言指南。这份文档适用于 IBM XLC/C++ for AIX V11.1 版本及其后续版本,直至新的...
浮点数和双精度浮点数(Double)在计算机中以二进制形式存储,而字节数组是数据在内存或磁盘上最常见的表示方式之一。在进行跨平台通信或者序列化时,通常需要将浮点数和Double转换为字节数组,反之亦然。这种转换...
【C/C++程序设计编程百例】中的知识点涵盖了C/C++语言的基础知识和高级技巧,主要体现在以下几个方面: 1. **基本语法与控制结构**: - `for`循环用于迭代,例如在绘制余弦曲线的例子中,用`for`循环控制`y`的递减...
C/C++程序的内存管理主要包括静态存储区、堆和栈三部分。静态存储区在编译时分配,生命周期与程序相同;栈用于存储局部变量和函数调用信息,由系统自动管理;堆则通过 `malloc`、`new` 等函数动态分配,程序员需手动...
5. **基本数据类型**:C/C++中的基本数据类型包括`char`(字符,通常占用1字节)、`int`(整数,根据平台不同,一般为4或8字节)、`float`(单精度浮点数,4字节)、`double`(双精度浮点数,8字节)以及布尔类型`...
- 第13题:条件表达式`a<b?a:c<d?c:d`在`a为假时,会检查`c,由于`c`为3,`d`为2,所以条件为真,取`c`的值3。 9. **循环计算**: - 第14题:不能完成求5!计算的程序段是`for(int i=1, p=1; i; i--) p*=i;`,因为...