目录
什么是NAN?
不同编程语言的NaN
为什么浮点数会搞出Infinity和NAN两种类型?
浮点数
小数点位置浮动的原因
浮点数和整数
浮点数指令
精确性
浮点数的类型
为什么叫浮点数?
小数点位置浮动的原因
IEEE 754起源于intel公司
IEEE 754标准
编程语言的浮点数都使用IEEE754吗?
浮点数指令
浮点数的精确性差?
浮点数操作丢失精度
什么是NAN?
NAN全称是Not a Number,常在浮点数运算中使用,首次引入NaN的是1985年的IEEE 754浮点数标准。如除以零、求负数的平方根等错误的操作,会返回NAN. 例如可以求一个负数的平方根,结果用isnan函数(来自math.h)返回真。
不同编程语言的NaN
- JS全局函数isNaN和ES6引入的Number.isNaN函数存在差异,后者更符合字面理解。
Number.isNaN(undefined)返回false,而全局isNaN(undefined)返回true.
为什么浮点数会搞出Infinity和NAN两种类型?
本质上,Infinity和NAN内部存储依然是一个浮点数,只是需要和正常的浮点数区分开。IEEE754标准规定浮点数有指数E和尾数M部分,标准规定当E等于255(E的最大值),可代表Infinity无穷和NAN非数两种。
- E == 255,M == 0:Infinity
- E == 255,M != 0: NAN
这意味着,其它任何有效的浮点数指数E都不会是255.
浮点数
浮点数相比定点数或者整数,为了处理小数点引入了指数,导致小数点的位置根据不同浮点数而不同,故名为Floating Point Number. 一般而言,IEEE754标准被大部分编程语言的浮点数使用,它节省了浮点数的保存空间。如不然,浮点数可能按每一位ASCII码保存,包括整数部分、小数点和小数部分,占用空间不可控制。
小数点位置浮动的原因
浮点数整数部分长度不一,为了统一整数部分和指数部分,把所有整数都转换成0.xx格式,造成小数点位置不一。
浮点数和整数
- 浮点数的位级存储和整数完全不同,整数1和浮点数1.0存储也截然不同。通过调试器查看int变量和float变量的内存存储,或者写一段dump字节代码比较其区别,还有一种方式,C/C++ %a格式串可用十六进制形式表达浮点数(其他编程语言可能不适用)。
- 不同浮点数位级存储也不相同,float和double是不同的。
- 浮点数和整数运算,整数会默认先转换成浮点数。
f = f + i;
cvtsi2ss xmm0,dword ptr [i]
addss xmm0,dword ptr [f]
movss dword ptr [f],xmm0
浮点数指令
早期计算机根本没有浮点数处理ALU,浮点数靠软件整数去模拟,性能极低。后来,加入了浮点数FPU,浮点数处理速度极大提升,比如xmm寄存器。
- double f = 2.25; // IEEE 754内存存储
- 00501056 movsd xmm0,mmword ptr [__real@4002000000000000 (0502108h)]
精确性
浮点数的表达方式利用整数位和小数位计算的2n数值(n可正可负)计算,必然出现不准确。1.5可精确表示,0.3却无法精确表示。有的书籍上提到,浮点数不要用==或!=判断,其实是考虑有不精确表达的可能。在商业银行金融领域,这是不能容忍的。市面上,只要是用IEEE 754标准表达的浮点数,运算一定是不精确的。
- COBOL编程语言是上古时期可以处理小数精确度很好的一门语言,因为它真的用模拟的形式保存小数点和小数位,而非IEEE 754这种压缩版。
- C#引入了decimal类型处理小数点更精确。如下两种不同类型变量输出的结果第一个会更精确。
decimal d = 3.14159265124m;
float f = 3.14159265123f;
浮点数的类型
尽管4字节的浮点数可表达相当大的数值,但对于人类而言,总不够用。一般而言,浮点数有3种类型,单精度的float和双精度的double以及更长的long double, 可参考:数据类型大小
- C语言为了区分float和double, 输入时用%f代表float, %lf代表double, 但对于输出%f和%lf作用相同。
- C语言中float类型是默认转换成double去处理,如下图所示。
- C99引入了long double (%Lf), 注意并不意味long double一定比double要长,根据编译器选择。
为什么叫浮点数?
浮点数相比定点数或者整数,为了处理小数点引入了指数,导致小数点的位置根据不同浮点数而不同,故名为Floating Point Number. 一般而言,IEEE754标准被大部分编程语言的浮点数使用,它节省了浮点数的保存空间。如不然,浮点数可能按每一位ASCII码保存,包括整数部分、小数点和小数部分,占用空间不可控制。
小数点位置浮动的原因
浮点数整数部分长度不一,为了统一整数部分和指数部分,把所有整数都转换成0.xx格式,造成小数点位置不一。
浮点数和整数有什么不同?
IEEE 754起源于intel公司
1980年,intel公司发布8087浮点数协处理器,它对浮点数的设计还算不错,被IEEE采纳为标准。它设计了3块,符号位、指数域和分数值。本质上是在较小的空间,如4字节或8字节,分成不同位域,存储更多数值的讯息,避免用一个字节表示十进制浮点数一位,造成空间浪费。
IEEE 754标准
IEEE 754是IEEE二进制浮点数算术标准(IEEE Standard for Floating-Point Arithmetic)的简称,于1985年首次发布,并在后续的1987年、2008年和2019年进行了修订。这是由国际电气和电子工程师协会(Institute of Electrical and Electronics Engineers,IEEE)制定的一种浮点数运算标准,也是20世纪80年代以来最广泛使用的浮点数运算标准,被许多CPU与浮点运算器所采用。大部分编程语言都采用IEEE 754标准作为浮点数标准,C语言诞生比它还早,后面也是采用此标准。
IEEE 754起源于intel公司
编程语言的浮点数都使用IEEE754吗?
对于主流的一些编程语言,例如C、Objective-C、C++、Swift、C#、Java和JavaScript都按照IEEE754标准实作浮点数。
浮点数指令
早期计算机根本没有浮点数处理ALU,浮点数靠软件整数去模拟,性能极低。后来,加入了浮点数FPU,浮点数处理速度极大提升,比如xmm寄存器。最早有FPU功能是intel的8087处理器。
- double f = 2.25; // IEEE 754内存存储
- 00501056 movsd xmm0,mmword ptr [__real@4002000000000000 (0502108h)]
浮点数的精确性差?
浮点数的表达方式利用整数位和小数位计算的2n数值(n可正可负)计算,必然出现不准确。1.5可精确表示,0.3却无法精确表示。有的书籍上提到,浮点数不要用==或!=判断,其实是考虑有不精确表达的可能。在商业银行金融领域,这是不能容忍的。
- COBOL编程语言是上古时期可以处理小数精确度很好的一门语言,因为它真的用模拟的形式保存小数点和小数位,而非IEEE 754这种压缩版。
- C#引入了decimal类型处理小数点更精确。如下两种不同类型变量输出的结果第一个会更精确。
decimal d = 3.14159265124m;
float f = 3.14159265123f;
浮点数操作丢失精度
- C# 提供了round-trip格式符R或者r可以确保浮点数在运算过程中没有丢失精度。
例如 string s = string.Format("{0:R}", float_val), 字符串s在后面被重新解析成浮点数不会改变。
浮点数指令 不同的浮点数类型 计算机存储单元bit
若文章对您有帮助,欢迎关注 程序员小迷 。助您在编程路上越走越好!
微风不燥,阳光正好,你就像风一样经过这里,愿你停留的片刻温暖舒心。
我是 程序员小迷 (致力于C、C++、C#、Android、iOS、Java、Kotlin、Objective-C、Swift、Shell、JavaScript、TypeScript、Python等编程技术的技巧经验分享),若作品对您有帮助,请关注、分享、点赞、收藏、在看、喜欢,您的支持是我们为您提供帮助的最大动力。