设为首页 加入收藏

TOP

浮点计算编程原理实现与应用 前言
2013-10-07 00:38:47 来源: 作者: 【 】 浏览:65
Tags:浮点 计算 编程 原理 实现 应用 前言

前言

本书内容

本书主要介绍基本计算算法的实现和代码分析,涉及任意长的整数计算、任意范围和精度的实数计算(包括定点运算和浮点运算)、常见数学函数的实现和Visual

C++(www.cppentry.com) 6.0(简称VC6)浮点库C形式的反汇编代码分析。

全书分两个部分:

第一部分讲述计算编程(www.cppentry.com)的基本原理与算法。自整型运算开始,步步推进直至建立通用的基本数学函数库。建立了支持整型运算的CGUINT和CGINT、支持定点运算的CFixedPoint、支持浮点运算的CFloatPoint和CSuperFloat。其中CFloatPoint和CSuperFloat是在IEEE浮点运算标准的基础上建立的,支持IEEE浮点运算标准的浮点格式和一般约定。

这几个C++(www.cppentry.com)模板几乎实现了常见的各种计算。而且,由于在设计和编码时采用了通用编程(www.cppentry.com)技术,使得CGUINT和CGINT可以支持任意长度的整型运算,CFixedPoint和CSuperFloat可以支持任意精度的实数运算。

第二部分讲述Intel公司的x87 FPU与Microsoft公司的VC6浮点库,涉及x87

FPU编程(www.cppentry.com)模型、VC6浮点库反汇编代码,深入分析了VC6浮点库的一些实现细节。

最后简要介绍了x87指令集和本书的源码。

写作缘起

我原是一名工科学生,毕业后成为一名工程技术人员,在专业领域工作了七八年,一直没能离开浮点运算。早年,我在x86/DOS上用FORTRAN计算弹道和轨道(那时还需要数学协处理器或浮点仿真库),后来转移到x86/Windows上使用C/C++(www.cppentry.com)。由于这些语言的编译器对浮点运算的支持相当完善,我几乎没有觉察到浮点运算的特别之处。唯一不快的是,我有时喜欢用汇编编写一些代码,但由于当初学习微机原理时没学x87指令,始终没能用汇编编写一行浮点代码。

我从事的工作需要编写计算程序。由于计算错误可能导致严重后果,我常常担心数学函数超出定义域、出现被零除、误差太大之类的问题。自然,代码总是有问题的,即使没有出现问题的代码看上去也很可疑。调试过程中,VC6的在线反汇编功能非常不错,常常显示下列代码:

FLD QWORD PTR [EBP+8]
CALL __fload_withFB
...
FCOMP QWORD PTR [__REAL@8@00000000000000000000]
FNSTSW AX
TEST AH 40h
这些代码在那时的我看来犹如天书,有时气得连把计算机砸掉的心都有了,有时又觉得那是对我的嘲弄。我小心地分析算法,检验各种参数,以避免一切可能的错误。例如,我曾写过类似下列可笑的代码:
cos_theta = x/sqrt( x*x + y*y );
if( cos_theta > 1.0 )
    cos_theta = 1.0;
else if( cos_theta < -1.0 )
    cos_theta = -1.0;
return acos( cos_theta );

之所以如此,是因为我担心浮点运算的误差以及浮点数表示的不精确会导致数学函数在边界上出现问题。例如,如果cos_theta的值是1.0,但由于浮点数可能带有随机误差,那么它的值可能是1.000000000000000034之类,而这会导致acos()失败,从而导致整个计算失败。我就是用这些可笑的技巧(有时没有这么可笑)来保证代码稳定的。显然,这种做法即使成功了,也没有什么可骄傲的。

后来,由于工作变动,我慢慢不再编写这类程序。我庆幸自己终于从尴尬的处境(我无法相信自己编写的代码是正确的,但必须相信它的结果)中脱身了,有段时间我看起了编译原理(这是整型的天下)和Java(这里没有x87指令),浮点运算和汇编就像原始丛林一样被生活在现代都市中的我忘却了。

可是有一天,不知哪儿出了问题。首先是一个同事问我NaN是什么意思,他像我当年一样遇到了浮点运算中最可怕的标记——NaN。编了超过十年计算代码的我告诉他,那是Not a Number的意思。的确没错,但这对他毫无用处。然后在一个网站论坛上,一个可怜的家伙问如何实现浮点除法。我告诉他,现在的通用CPU都支持浮点运算,没必要关心浮点除法。可他说他必须实现一个浮点除法,我猜想他是一个偷懒的学生,便不再理他。当天晚上,一个同事走进我的宿舍,说我当年编写的一个程序怎么结果都不对。过去的恐惧一下子又浮上心头。我打开源码,从出错的地方硬着头皮反向查看,没有发现任何可疑之处。过了半个多小时,我突然意识到可能是他输入了错误的数据。打开数据文件,我发现他将高低角和方位角颠倒了。他走了以后,我又翻看了一下代码。在编写一般的程序时,通常我会写大量的检测代码。一旦程序出错,通常在出错的地方就会有告警提示(例如提示某个Win32 API返回的句柄无效),但在编写浮点代码时,由于对浮点运算的底层机制不明白,我总是有些缩手缩脚,不知怎样编写合适的检测代码(上面那些可笑的代码毫无用处)。只有当错误的运算结果出来时才发觉计算出错了,而错误的源头却不知道在哪儿。往往一个函数出了差错,却要在几个积分循环以后在另一个函数那儿导致计算无法进行(出现恐怖的NaN、INF或定义域错误)。对这类错误,除了搜山似地翻看源码并作种种假设猜想之外,毫无他法。

那段时间我正空闲。于是,我对自己说,那就看看x87指令吧,一劳永逸地清除这虚幻的恐惧。既然已经知道了上百条x86指令,那么再多几十条x87指令也不会太难。这是2004年底的事情。

我想,看些别人写好的文章或者书也许有助于理解。在网上搜寻了许久,除了几篇简单的x87指令说明(简单到只有指令本身和指令名字的翻译)之外,几乎任何有价值的东西都没找到。在林林总总无所不有的编程(www.cppentry.com)世界,浮点运算似乎是一块被人遗忘的角落。最后,只好从Intel公司的网站上下载了编程(www.cppentry.com)手册(文献[2]),从一个英文网站下载了一篇关于IEEE

754标准的演讲稿(文献[8]),从另一个英文网站下载了IEEE

854标准(文献[9]),后来又买了一本密码编程(www.cppentry.com)方面的书(文献[1],里面涉及大整数运算)。这就是我开始学习计算编程(www.cppentry.com)的所有资料。在学习过程中,我多次想到,要是当年编写浮点代码时知道这些东西,那该多好啊!可是现实就是这么嘲弄人,在我需要的时候,我不懂,在我懂得的时候,已不需要。

由于资料大都是英文的,看得多了,有时也翻译一些,在翻译的同时还加上自己的理解发挥一下。有时遇到不好理解的段落,就编上一段代码测试一下。这些东西多了以后,便显得杂乱无章,我自然就整理了一下。整理的时候发现,无论怎样,它们也无法连接成一个整体,需要在中间添加一些东西。于是,出现了两三篇文章。同时,为了了解实际中如何进行x87

FPU编程(www.cppentry.com),我开始反汇编VC6浮点库。经过一段时间以后,我想我也可以像VC6一样编写自己的浮点库了,可重复别人的代码毫无意义,我就把注意力集中在如何实现浮点运算的基本算法上。开始是基本的数学函数,后来连加减乘除也实现了。自然,这些东西已不是几篇文章所能组织起来的了,又不想这样凌乱地堆放着,写书的想法开始出现。这是2005年夏天的事情。

2005年国庆,利用七天假期,我写下了完整的一章(第7章的原稿)。随后,我一边写,一边修饰代码,一边调整章节。在这个过程中,我慢慢感觉到,仅仅关注浮点运算是不行的。一方面是因为浮点运算需要大整数运算的支持,而大整数运算超出了常规整型(例如C/C++(www.cppentry.com)中的int和long)的运算范围,是一个不能忽视的问题;另一方面是因为常规的浮点运算存在精度限制问题。为什么不一劳永逸地实现任意类型、任意精度的计算呢?例如,计算π到小数点后1000位怎么样?于是,任意长度的整型运算和任意精度的实数运算进入了我的视野。开始,我以为这是一个不可实现的目标,但慢慢地还是有所进展,最终一个小小的计算系统出现了。这是2005年底的事情。

最初的热情过后,剩下的就是时间和毅力的问题了。

关于读者

由于本书是从学习、理解计算编程(www.cppentry.com)的角度编写的,因此只要你对计算有兴趣或有需要,那么你就是本书希望的读者。

算法的数学部分只涉及微分函数,因此只要受过本科教育均不会有困难。演示代码是用C++(www.cppentry.com)语言编写的,但只涉及基本的模板、函数重载、操作符重载。有一个地方(CGUINT优化部分)有嵌入式汇编,但内容不多,而且不是基本的东西,可以不看。不过,需要有些x86汇编基础以理解x87浮点指令部分和VC6浮点库反汇编部分,但要求不高。

算法实现部分有些代码需要一些编程(www.cppentry.com)经验才能很好理解(例如数据的内存结构),有些部分使用了VC6编译器的特性(如嵌入式汇编),但难度均不高,只要有兴趣,即使是C++(www.cppentry.com)语言初学者也可以通过努力读懂。一些细节可能有点晦涩(如弱规范数运算),需要一些时间才会慢慢明白。

关于代码

写编程(www.cppentry.com)方面的书或文章有一个实际问题,就是如何组织显示代码。如果将代码完整地印刷出来,有两方面的问题:一方面代码常常很长,与关心的问题无关的代码尤其长得出奇,这当然浪费了纸张(也浪费读者的金钱和时间);另一方面,在纸面上、在没有代码管理工具(如集成环境的源码编辑器)的情况下,读者怎么读这些代码而不感到厌烦或头晕呢?可是如果在书中不出现代码,只讲数学形式的代码算法,将编程(www.cppentry.com)当作算法分析处理,读者又怎能熟悉那些并不能在算法中表现出来的细节呢?

可见,代码不可能不要,但也不能太多。但是,多少是合理的?对于某些喜欢编码的人而言,没有大量代码的书简直就是垃圾。他们甚至不愿翻这种书,而是直接阅读代码代替看书。对于另一类人,他们看见代码就头晕,喜欢数学形式或伪码形式的算法描述,认为这才是算法的精华,代码中琐碎的细节处理只是实现算法必须忍受的折磨。

这些思考决定了本书的大致特征,即在代码的基础上向算法分析靠拢。读者可以简单地认为本书是为代码编写的、含有算法解说的大型注释。它可以脱离计算机,不用在屏幕前阅读。当然,这不是说不用看代码,而是说核心代码均可以在书中看到。

本书的代码是演示性质的,但实现时考虑到了一些效率问题,因此一些代码可以直接使用,或者经过简单的修改就可使用。不过,出于可以理解的原因,这些代码只进行了简单的测试,在一些特性上也没有严格遵循IEEE标准,因此作者不能保证这些代码的可靠性,使用这些代码导致的后果应由使用者自己承担(使用者应该读懂代码,了解代码产生的结果)。

本书代码可在http://www.cmpbook.com下载。

读者购买本书就自动获得了本书代码的使用权,可以在任何场合使用。如果读者使用了本书代码或对代码作了修改,请在显眼处说明。

本书所有代码都是在VC6中编译通过的,没有在别的环境中作过测试。如果在别的开发环境下编译运行本书的代码,可能需要一些调整。

联系作者

由于工作关系,我很难有上网的机会。读者如果有需要,可以通过出版社与我联系。


作  者

【责任编辑:云霞 TEL:(010)68476606】

回书目      下一节

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇浮点计算编程原理实现与应用 目录 下一篇12月TIOBE编程语言排行榜 C或C++..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: