各种编程软件介绍

本文将介绍10多种不同的程序设计语言,以及如何下载它们的免费的编译器。

20年后,我们用什么样的语言?也许现在谁都不好 回答,20年前的程序员们会告诉你用汇编吧,今天人们也许会告诉你用c语言(c++?)吧。那么20年后呢,也许不是c语言了吧。下面都是所谓的非主流语 言,不过它们的设计思想、所能够完成的功能,绝对不比c语言差。也许将来它们会成为主流,也许不会,可是不管怎样,它们都有自己的闪光之处。

Prolog

人工智能领域常用的语言,开发自然语言分析,专家系统,以及所有和智能有关的程序,都非常拿手。可以到我的主页来学习这门语言 http://cdtzx.swiki.net

----visual prolog
www.visual-prolog.com
顾名思义,这是一个可以制作界面的Prolog,有试用版本下载,大概20M左右。这个prolog版本需要对谓词以及数据进行声明,就像C语言一样。因此在使用的时候比较复杂,不过更加适合编制较大的程序。编译出来的程序可以直接运行。

----amzi prolog
www.amzi.com
这 个prolog版本包含解释器、编译器,不过编译出来的程序不能够直接运行,需要运行器运行。可以很方便的和其它语言(例如visual basic,java,C,CGI)连接,开发智能程序。解释器的运行效率较低。它所说使用的语法体系和visual prolog不同,程序需要进行适当的修改才能够在visual prolog中运行。

----SWI-Prolog
http://www.swi.psy.uva.nl/projects/SWI-Prolog/
我 没有怎么使用过这个版本的prolog解释器,不过它的运行速度要比amzi prolog的解释器快,和amzi的编译之后的程序差不多快,如果下载图形软件包XPCE的话,还可以开发有界面的程序。它的语法和amzi prolog相同,程序可以通用,不过内部谓词有些不同,有时候需要修改一下。

----Turbo prolog
http://magicpage.myetang.com/
Dos版本的prolog,有开发界面,可以编译成可执行文件,语法和visual-prolog相同,不过内部谓词有许多出入。

----B prolog
http://www.cad.mse.kyutech.ac.jp/people/zhou/index.html
好 像是中国人开发的prolog软件,据说比其它的prolog运算速度都要快,我曾经在linux下面使用过这个prolog,也有window版的,不 过没有什么集成开发环境。语法和其它的几个都不太相同,需要适当的修改程序才能够在此环境下运行。此prolog提供了许多测试速度的解谜题的程序,这个 版本的prolog支持constraint程序设计。

----strawberry prolog
http://www.dobrev.com
1兆的容量,包括完整的开发界面,帮助,例程,提供了几个棋类游戏的源程序。可以直接开发有界面的prolog程序,共享版不能够编译,就解释执行吧

----Sicstus Prolog
http://www.sics.se/sicstus/
Sicstus Prolog无疑是Prolog版本中最出色的,虽然它并不是免费软件,但是可以下载到有时间限制的试用版本,而且只要修改时间也可以无限期的使用下去 (过期之后修改时间也不会有问题)。它语法与amzi prolog类似,都属于ISO标准,内部胃词丰富,提供了丰富的库,例如集合、图、带权图等等。支持unix和windows等各种操作系统平台。支持 constraint程序设计。

---EZY Prolog
http://www.ezy-software.com/
visual prolog开发的一个有趣的prolog解释器,和visual prolog一样,可以直观的设计界面,并且有支持老trubo prolog程序的模式,如果你手头上有很老的turbo prolog源程序,又不想修改的话,可以看看。

Lisp

人工智能语言的老大哥。语言格式只有一个形式:列表,所以也叫做表处理语言,这可不是一般的表,是可以包容任意结构的表,有了它,你还用c语言来写链表,二叉树的程序么?学习数据结构不妨使用lisp,让你更加关心算法,而不是数据如何在计算机内部表达。

----xemacs
www.xemacs.org
与著名的guns emacs编辑器的起名,并且界面更加友善,内带emacs lisp, 和许多使用lisp编写的工具软件,例如calc, 是一个功能强大的计算器,支持符号运算,有全部的源程序,如果能够好好研究这些源程序,收获一定不小。

----Allegro CL
common lisp
http://www.franz.com, windows下的common lisp集成开发环境, 60天试用。

----lisp work
common lisp
http://www.xanalys.com/ 无限期使用,没有任何功能限制

----corman lisp
http://www.cormanlisp.com
完全免费

Scheme

这是lisp的一种方言,比lisp更加标准化。

http://mitpress.mit.edu/sicp/
这里有一本非常好的介绍编程技术的书,使用的语言是lisp/scheme。在这里还可以下载到Scheme的解释器,基本上是模仿emacs作的。

 

http://www.drscheme.org/
DrScheme是一个Scheme语言的交互式的集成开发环境。非常适合于教学使用。支持多种语言级别(初级、中级、高级等等),有丰富的界面库,支持TCP/IP。内带详细的帮助和教程。

functional language

这是一类语言,叫做函数型程序设计语言。是一种非常高级的语言。一种基于λ演算和在70年代后期才发展起来的新语言类型。大多数程序设计语言明显地规定要执 行操作的次序。次序的详细规定是很需要的,因为语言的语句对程序的变量有"作用",如果改变这些作用的次序,就可以改变产生的最后值。但是函数型语言却没 有这种性质。在这个意义上,函数型语言能建立可计算性的数学公式模型。让我们来看一个简单的例子:

qsort :: [a] -> [a] | Ord a
qsort [] = []
qsort [a:xs] = qsort [x \\ x<-xs | x=a]

 

这段程序就是快速排序的代码,你看有多么简洁,并且它的这个qsort可以对任何类型的数据进行排序(只要这种数据可以比较大小)。想读懂上面的程序么?那么下载下面的clean, 或者haskell,好好研究吧,祝你有新的发现。

----clean
http://www.cs.kun.nl/~clean/
并行的函数型语言,可以把源程序编译成exe文件,带有丰富的库,从tcp/ip, 到界面设计,到游戏开发,无一不全。

----haskell
http://www.haskell.org/hugs/
hugs是haskell的免费编译器,语法和clean相似,不过是解释执行,因此易于学习。

---caml
http://caml.inria.fr/
又一个函数型语言。

mozart oz

www.mozart-oz.org

mozart oz 是具有魔力的语言。它融合了目前几种流行的程序设计思想,我们叫它多范式语言。它是面向对象的语言,它是函数型的语言,它是约束逻辑 (constraint)的语言,它是并发式的语言,它还是分布式的语言,几句话很难概括它的功能。最好去它的网站看看吧,下载一个慢慢研究?
他使用emacs作为开发界面,因此如果你想在windows下使用本语言,首先需要安装emacs for windows(也可以在mozart的网上找到,也可以去www.gnus.org去找,也可以安装xemacs), 如果你安装了emacs 那么你也就同时获得了emacs lisp, 呵呵,收获不小。
为了提起您的兴趣,请思考如下的问题如何编程解决,然后你可以在mozart中找到惊人简单的解决方案。
15个人每天出去玩,每天分为5组,每组3人,玩一个星期,使得任何两个人都曾经在一组中玩过,你如何安排?

J

www.jsoftware.com

不要和java搞混淆了。它是一种面向阵列的语言,也就是说矢量,矩阵,以及高次数组都是它的最基本的数据类型,J中引入了大批量的运算符,以及独特的算式 分析方法,大幅度的扩展了数学算式的表达能力。 例如如果你要算从1加到100, 用c怎么做? J的程序是:+/i.100 对,就这么短,一个表达式解决了问题,事实上,使用表达式编写出来的程序异常简洁,虽然初看上去很难读懂,一旦掌握了J语言,你就会发现,原来你可以用只 有c语言1/20的字符表达同样的功能。

forth

http://www.forth.org/compilers.html

forth是一种可扩展的,交互式的语言。最初为小型的嵌入式电脑设计的,现在它几乎可以在任何主流的芯片上运行。 在电子表格,专家系统, 多用户数据库,和分布式实时控制系统中有广泛的应用。
表 面来看,forth是一种基于堆栈的概念机。例如如果要计算 (3+4)*5 ,我们的程序就是:3 4 + 5 * . 首先把3和4入堆栈,然后调用+子程序,+把堆栈的最顶上两个元素取出(也就是3和4)进行加法运算,然后把结果入堆栈,然后把5入堆栈,然后调用*子程 序,把最顶的2个元素,也就是7和5取出,并进行乘法运算,然后把结果入堆栈,最后的.把结果从堆栈中取出。 事实上这是一种简单有效的概念机。当然forth远远不止这些,它有什么样的功能,就由你去发掘了。

Logo

被称为最佳的启蒙语言,事实上它的功能远远不止启蒙这么简单。一切别的语言能够完成的它也能够完成,只是更加简洁一些,通常logo是使用lisp编写的,我们就可以想象它的高度灵活性了。

----MSWlogo
http://www.softronix.com/
这个网站还有个逻辑数字电路模拟的软件,很有意思,再也不用为什么触发器 门电路之类的发愁了。

----StarLogo
http://www.media.mit.edu/starlogo
starlogo的网站如是说:
StarLogo是一个可以编程的建模环境,用来研究分散系统的运行机制。所谓分散系统是指:没有组织者而组织,没有协调者而协调的系统。使用StarLogo你可以对许多现实世界中的现象进行建模并且观察研究,例如鸟群、交通、蚂蚁以及市场经济。
StarLogo是一种特殊的Logo语言,和传统的Logo语言一样,你可以通过向海龟发命令来作图。除此之外,Starlogo容许你并行的控制上千个海龟,并且为这些海龟设定不同的行为模式。StarLogo非常适合于研究人工生命。

---NetLogo
http://ccl.northwestern.edu/netlogo/
和starLogo属于同种软件,不过感觉用起来更加方便一点,自带的模型实例就有近百个,内容包括生物、化学、物理、社会、热力学等众多方面。另外它的网站上有许多实际的模型可供下载研究,还能把你编写的模型制作成applet,这样就可以在线运行了。

python

www.python.org

python 是一种解释型、交互式、面向对象的语言,我们经常拿它来和Tcl Perl Scheme Java来比较。它有非常清晰的语法,有模块,有类,异常处理,高级的动态数据结构。它比perl更加易学,功能更加强大。python采用动态数据结 构,也就是说变量没有数据类型,这一点和Lisp十分相似,在python中所有事物都是对象(object),字符串、函数以至于类和模块。这种面向对 象的概念和smalltalk很相似。并且自带了丰产丰富的模块库。对于初学者,python很适合于学习编程思想,而不会让读者为了繁杂的语法而头痛。 对于高级用户,python是最出色的脚本语言,它可以很容易的内嵌某个软件中,作为那个软件的扩充,例如著名的3D设计软件blender就可以使用内 嵌的python脚本语言来设计复杂动画。

ruby

http://www.ruby-lang.org/en/日本人发明的类似于python的语言,不过据说它的设计上比python更加先进,纯面向对象,吸收了java, smalltalk,perl等语言的长处,可能是最新的语言之一。

smalltalk

面向对象的程序设计语言的鼻祖,并且正在蓬勃的发展,没有过时。它是纯面向对象的语言,就连整数也是对象。开放环境也非常集成,如果感兴趣可以到一下网站下 载,绝对有耳目一新的感觉。举个例子,循环语句在smalltalk中是向一个整数对象发送消息:10 timesRepeat: [ teresa moveRight: 10 ].其中timesRepeat:为消息名称,10为接受消息的整数对象,[ teresa moveRight: 10 ].是消息的参数,这又是smalltalk强大的地方,它可以把一段程序作为参数传递给某个对象!!!

http://www.squeak.org/ 这是一个非常有趣的smalltalk版本,看上去就像在你的电脑上模拟了另外一套完成的窗口系统,这里面的窗口更加利害,你甚至可以旋转它,不看不知道,看了才发现还有这么奇妙的语言,这么奇妙的开发环境。10M左右

http://www.cincom.com/scripts/smalltalk.dll/home.ssp,这个版本比较实用,有详细的帮助,可以开发真正的windows程序。30M左右

http://www.object-arts.com/ 这里提供的免费smalltalk版本只有3M不到,如果你想先尝试一下这种语言的话,可以下载这个。

Icon

这个语言和图标没有什么关系,不要误解了。这是一种很神奇的语言,虽然目前已经有几年没有更新版本了,不过我觉得它的许多思想都是很先进的。

http://www.cs.arizona.edu/icon/
在语法形式上与c,pascal很相似,但是功能却更加强大,以下是它的一些特点:
Icon的表达式可以产生一系列的值,而不是一个值。
面向目标的求值方式,可以自动的搜索正确的解答(这一点和prolog很像)
强大的字符串处理功能
当然,至于链表、集合、甚至词典(dictionary,也可以叫做hash表)都是它的基本数据类型。内存也是自动管理的,无需担心内存泄漏或者溢出等琐碎的问题。
他特别适合于文本分析、文本编辑、数据格式化、人工智能、专家系统、符号运算的方面的编程。
下面给几个简单的例子:
every f(i to j) ---Icon
for(k=i;k<=j;k++) f(k); ---C
every write(find("or",sentence)) ---输出sentence中所有子字符串or的位置

Graphical programming language

这类语言很有趣,因为用它写程序不是打字,而是绘图。最著名的应该是Labview所使用的G语言了吧,不过它无法免费使用。

http://vvvv.meso.net/tiki-index.php
vvvv主要应用在实时视频合成方面,它提供了一个绘图式编程环境,很有趣,而且个人使用是免费的。

C

最后我们还是回到c语言,毕竟这是目前最流行的语言,如果你不想用盗版,不想安装100多兆的垃圾(大多数初学者不可能完全使用borland c++ builder 或者visual c++的全部功能,而只是用来学习c语言本身),也不想在dos的edit样子的面孔下,使用Tc编程序,那么try下面的东东吧。3M的大小绝对值的下 载。

http://www.cs.virginia.edu/~lcc-win32/index.html

如果想下载C++的编译器,去http://www.bloodshed.net/devcpp.html看看,这个集成开发环境使用Delphi编写,C++编译器是Mingw编译系统。


快速求1/sqrt(x)

RY DSP开发 2005/04/13

1/sqrt(x)在许多计算领域都是非常常用的,例如3D计算中的向量正规化等等。本文给出一个神奇的快速求1/sqrt(x)的程序。

今天做优化声音分离程序的工作,发现其中求复数的模的倒数的计算数量相当大,于是就在网上找时候有比1/sqrt(x)更快的方法,还真让我找到了。采用这个优化算法之后,程序运行时间从14秒提升到了10秒,效果还是相当惊人的。那么让我们来看看这个程序吧。
float InvSqrt(float x){
float xhalf=0.5f*x;
long i=*(long*)&x;
i=0x5f3759df - (i>>1);
x=*(float *)&i;
x=x*(1.5f-xhalf*x*x);
return x;
}

倒数第二行的x=x*(1.5f-xhalf*x*x);是牛顿迭代法,这个在一般的数值计算的书中都能找到,关键是它计算初期迭代值的方法比较奇特,使得 只需要一次迭代就足够精确了,当然如果想要更加精确的结果的话,就多来一次迭代即可。它直接把浮点转换为整形来计算,还出现了一个神奇的数: 0x5f3759df,这个数字是加快算法的核心。它是怎么算出来的呢,在网络上搜索一下这个数字吧。原来这段程序是著名的游戏Quake 3的一个函数。介绍这个算法的文章可以在http://www.lomont.org/Math/Papers/2003/InvSqrt.pdf 下载。这篇文章从理论上分析了0x5f3759df的来历,并且提出了一个更加精确的数:0x5f375a86。如果各位有耐心的话不妨看看他的求解过程,写得很精彩,有时间的话真想把它翻译成中文。


用递推数列计算正弦波

RY DSP开发 2005/04/12

本文介绍快速计算正弦波的方法,并且就速度和精度问题进行一些讨论。

在DSP运用中,经常需要产生正弦波。如果 直接用c的数学函数sin,当然可以产生正弦波,但是由于sin函数本身的效率很低,产生正弦波所需要的MIPS就会占去DSP处理能力的相当大的一部 分。本章介用递推数列算正弦波的方法,先介绍原理,推导出递推公式,然后用浮点小数实现计算,再用定点小数进一步优化算法,最后进行误差分析,并提出更精 确的定点小数算法。

先来看看如何推导出递推数列的公式。
我们所要产生的正弦波,其实是一系列的整数,把这些整数按照一定的取样频率发送给数模转换器,就可以变成真正的正弦波了。假设取样周期是Ts,产生的正弦波的圆频率为w,那么我们需要产生的数列就是:
sin(0), sin(w*Ts), sin(2*w*Ts), ... sin(n*w*Ts)
假设f(n)= sin(n*w*Ts),则问题就变成,从f(n-1), f(n-2), f(n-3),..., 如何计算f(n)了。解决了这个问题,也就找到了递推公式。
下面是这个递推公式的求解过程,假设x=w*Ts:

公式:sin( a + b) = sin(a)*cos(b) + cos(a)*sin(b)
sin( x + (n-1)x ) = sin(x)*cos( (n-1)x ) + cos(x)*sin( (n-1)x )
公式:Sin(a)*cos(b) = 1/2 * [ sin( a+b ) + sin( a-b ) ]
sin(x)*cos( (n-1)x ) = 1/2 * [ sin(nx) - sin( (n-2)x ) ]
sin(nx) = 1/2 * [ sin(nx) - sin( (n-2)x ) ] + cos(x)*sin( (n-1)x )
sin(nx) = 2*cos(x)*sin( (n-1)x ) - sin( (n-2)x )

我们看到这个递推公式是:
f(n)=2*cos(w*Ts)*f(n-1) - f(n-2)
也就是说只要知道最初始的两项f(0)和f(1),就可以计算出整个正弦波了。

根据上面的递推公式,很容易写出下面的正弦波计算程序。只要事先计算一次sin(w*Ts)和cos(w*Ts),以后的值就可以通过递推公式得到,所以计算一个值所需要的工作就是一次乘法,一次加法,两次变量复制而已了。

float y[3] = {0, sin(w*Ts),0}; // y(n), y(n-1), y(n-2)
float a1=2*cos(w*Ts);
float a2=-1;
float singen(){
y[0]=a1*y[1]+a2*y[2];
y[2]=y[1];
y[1]=y[0];
return y[0];
}


假如我们需要产生取样频率为8KHz的440Hz的正弦波,那么a1=2*cos(2*pi*440/8000)=1.8817615,而y[1]=sin(2*pi*440/8000)=0.33873792。

现在看如何用定点小数来更快的计算正弦波。我们使用16bit也就是short型的整数来表示定点小数。首先需要决定的是小数的Q值,虽然我们最后计算的正弦波的值都是小于1的,但是在计算过程中需要用2*cos(w*Ts),而这个值最大为2,所以我们选择的Q值必须至少最大能表示2。这里我们选择Q14,Q14的定点小数能表示-2到2的取值范围,对于本例的正弦波计算正好合适。1.8817615的Q14值是1.8817615*2^14=5550=0x786F,同样0.33873792的Q14值为0x15AE。

下面就是完整的计算8KHz取样频率的400Hz的定点小数的正弦波的程序。

short y[3] = {0, 0x15AE,0}; // y(n), y(n-1), y(n-2)
short a1=0x786F;
short a2=0xC000;
short singen(){
y[0]=( (long)a1*(long)y[1]+(long)a2*(long)y[2] )>>14;
y[2]=y[1];
y[1]=y[0];
return y[0];
}

使用定点小数计算不但速度比浮点更快,而且计算得出来的值是整数,这个数值可以直接传递给DAC(数模转换器)转换为模拟的声音信号,如果使用浮点小数计算的话,还必须把浮点数转换为整数才能传递给DAC

使用定点小数计算必须仔细分析误差,下面来看看我们产生的正弦波的误差是多少。定点小数计算中的误差就是由定点小数表达精度决定的。在上面的例子中我们用0x786F表示1.8817615,这存在一定的误差,把Q140x786F再转换为浮点数就是0x786F/2^14=1.8817749,我们可以看到相对误差非常小,也就是说最终得到的正弦波在频率上的误差也是非常小的。

但是,定点小数并不是什么时候都这么精确。例如如果用CD音质的取样频率44100Hz来产生100Hz的正弦波,那么a1=2*cos(2*pi*440/44100)= 1.9960713,这个数转换为16比特的Q14的值是0x7fc0。我们可以看到这时定点小数已经十分接近0x7fff了,最终产生的正弦波的频率也会有很大的误差。为了能够精确地计算这样的正弦波,必须使用32bitQ30定点小数。关于32bit定点小数的计算方法将在别的章节介绍。

另外上面的singen函数每调用一次只产生一个值,如果要产生实时的正弦波的话,函数的调用频率和取样频率相同,DSP的负担相对比较大。一般DSP计算都采取块计算方式,一次计算n个(例如64)个取样值,这样不但减少了函数的调用负担,也可以减少中间的内存移动的次数(y[2]=y[1];y[1]=y[0];)。


DSP基础--定点小数运算

RY DSP开发 2005/04/11

许多DSP芯片只支持整数运算,如果现在这些芯片上进行小数运算的话,定点小数运算应该是最佳选择了,此外即使芯片支持浮点数,定点小数运算也是最佳的速度选择。

在DSP 世界中,由于DSP芯片的限制,经常使用定点小数运算。所谓定点小数,实际上就是用整数来进行小数运算。下面先介绍定点小数的一些理论知识,然后以C语言 为例,介绍一下定点小数运算的方法。在TI C5000 DSP系列中使用16比特为最小的储存单位,所以我们就用16比特的整数来进行定点小数运算。

先 从整数开始,16比特的储存单位最多可以表示0x0000到0xffff,65536种状态,如果它表示C语言中的无符号整数的话,就是从0到 65535。如果需要表示负数的话,那么最高位就是符号位,而剩下的15位可以表示32768种状态。这里可以看出,对于计算机或者DSP芯片来说,符号 并没有什么特殊的储存方式,其实是和数字一起储存的。为了使得无论是无符号数还是符号数,都可以使用同样的加法减法规则,符号数中的负数用正数的补码表 示。

我们都知道-1 + 1 =0,而0x0001表示1,那么-1用什么来表示才能使得-1 + 1 =0呢?答案很简单:0xffff。现在就可以打开Windows的计算器,用16进制计算一下0xffff+0x0001,结果是0x10000。那么 0x10000和0x0000等价麽,我们刚才说过用16比特来表达整数,最高位的1是第17位,这一位是溢出位,在运算寄存器中没有储存这一位,所以结 果是低16位,也就是0x0000。现在我们知道负数的表达方式了。举个例子:-100。首先我们需要知道100的16进制,用计算器转换一下,可以知道 是0x0064,那么-100就是0x10000 - 0x0064,用计算器算一下得0xff9c。

还有一种简单的转换符号的方法,就是取反加一:把数x写成二进制格式,每位0变1,1变0,最后把结果加1就是-x了。

好, 复习了整数的相关知识之后,我们进入定点小数运算环节。所谓定点小数,就是小数点的位置是固定的。我们是要用整数来表示定点小数,由于小数点的位置是固定 的,所以就没有必要储存它(如果储存了小数点的位置,那就是浮点数了)。既然没有储存小数点的位置,那么计算机当然就不知道小数点的位置,所以这个小数点 的位置是我们写程序的人自己需要牢记的。

先以10进制为例。如果我们能够计算12+34=46的话,当然也就能够计算1.2+3.4 或者 0.12+0.34了。所以定点小数的加减法和整数的相同,并且和小数点的位置无关。乘法就不同了。 12*34=408,而1.2*3.4=4.08。这里1.2的小数点在第1位之前,而4.08的小数点在第2位之前,小数点发生了移动。所以在做乘法的 时候,需要对小数点的位置进行调整?!可是既然我们是做定点小数运算,那就说小数点的位置不能动!!怎么解决这个矛盾呢,那就是舍弃最低位。 也就说1.2*3.4=4.1,这样我们就得到正确的定点运算的结果了。所以在做定点小数运算的时候不仅需要牢记小数点的位置,还需要记住表达定点小数的 有效位数。上面这个例子中,有效位数为2,小数点之后有一位。

现在进入二进制。我们的定点小数用16位二进制表达,最高位是符号位,那么有效位就是15位。小数点之后可以有0 - 15位。我们把小数点之后有n位叫做Qn,例如小数点之后有12位叫做Q12格式的定点小数,而Q0就是我们所说的整数。

Q12 的正数的最大值是 0 111 . 111111111111,第一个0是符号位,后面的数都是1,那么这个数是十进制的多少呢,很好运算,就是 0x7fff / 2^12 = 7.999755859375。对于Qn格式的定点小数的表达的数值就它的整数值除以2^n。在计算机中还是以整数来运算,我们把它想象成实际所表达的值 的时候,进行这个运算。

反过来把一个实际所要表达的值x转换Qn型的定点小数的时候,就是x*2^n了。例如 0.2的Q12型定点小数为:0.2*2^12 = 819.2,由于这个数要用整数储存, 所以是819 即 0x0333。因为舍弃了小数部分,所以0x0333不是精确的0.2,实际上它是819/2^12 =0.199951171875。

我们用数学表达式做一下总结:
x表示实际的数(*一个浮点数), q表示它的Qn型定点小数(一个整数)。
q = (int) (x * 2^n)
x = (float)q/2^n

由以上公式我们可以很快得出定点小数的+-*/算法:
假设q1,q2,q3表达的值分别为x1,x2,x3
q3 = q1 + q2   若 x3 = x1 + x2
q3 = q1 - q2   若 x3 = x1 - x2
q3 = q1 * q2 / 2^n若 x3 = x1 * x2
q3 = q1 * 2^n / q2若 x3 = x1 / x2
我们看到加减法和一般的整数运算相同,而乘除法的时候,为了使得结果的小数点位不移动,对数值进行了移动。
用c语言来写定点小数的乘法就是:
short q1,q2,q3;
....
q3=((long q1) * (long q2)) >> n;
由于/ 2^n和* 2^n可以简单的用移位来计算,所以定点小数的运算比浮点小数要快得多。下面我们用一个例子来验证一下上面的公式:
用Q12来计算2.1 * 2.2,先把2.1 2.2转换为Q12定点小数:
2.1 * 2^12 = 8601.6 = 8602
2.2 * 2^12 = 9011.2 = 9011
(8602 * 9011) >> 12 = 18923
18923的实际值是18923/2^12 = 4.619873046875 和实际的结果 4.62相差0.000126953125,对于一般的计算已经足够精确了。