博文

浮点数的比较(2012-02-02 00:05:00)

摘要:(摘自 http://blog.csdn.net/quickbasic411/article/details/5921420)

首先,这个不算原创,原文是洋文的,我翻译了一下 写这个文章的人绝对是个大师,虽然知识并不是很深奥,不过想法真的很不错,值得学习 两个月前忽然看见的这篇文章,昨天仔细读了一遍,翻译了一下,原文在此   http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm     这是我翻译的,里面有些地方翻译的不太对,有些地方我也不懂,你们谁要是看懂了就告诉我      浮点数的比较 Bruce Dawson 两数完全相等 整型数是精确的,浮点数并不是那样。举个简单的例子,0.2这个数无法用二进制的浮点数精确表示,并且有限的精度意味着微小的误差在经过多次操作后会改变结果。不同的编译器和CPU架构使用不同的精度存储临时数据,所以计算结果取决于你的运行环境。所以当你计算出结果并与你预期的结果进行比较时,会发现它们也许大不一样。   换句话说,如果你在计算中做如下比较: if (result == expectedResult) 这个比较的结果几乎不可能为真。如果结果确实为真,那说明这个结果是不稳定的——输入数据、编译器、CPU的微小改变也许会使程序产生截然不同的结果。 比较e-绝对误差 既然浮点数的计算引入了一点点不确定性,那么我们忽略它,方法就是判断两个数是否足够近。不管是通过什么方法(误差分析、测试、甚至是瞎蒙),如果你认为两个数只要相差不到0.00001就算相等的话,你可以将程序改成这样: if (fabs(result - expectedResult) < 0.00001) 这个最大的误差值称为(epsilon)   绝对误差可能有点用处,不过大家不常用它。大部分时候,误差是指的一个百分比。大家不用绝对误差的原因是,一个1.0的误差,你不知道结果是一百万还是0.1。   对于有限精度的浮点数还有一个更杯具的问题,就是如果绝对误差太小的话,有限的精......

阅读全文(11151) | 评论:4

数据结构之概念介绍(2012-02-02 00:02:00)

摘要:摘抄
由于原网页已不存在,图片失效         数据结构是计算机科学与技术专业的专业基础课,是十分重要的核心课程。所有的计算机系统软件和应用软件都要用到各种类型的数据结构。因此,要想更好地运用计算机来解决实际问题,仅掌握几种计算机程序设计语言是难以应付众多复杂的课题的。要想有效地使用计算机、充分发挥计算机的性能,还必须学习和掌握好数据结构的有关知识。打好“数据结构”这门课程的扎实基础,对于学习计算机专业的其他课程,如操作系统、编译原理、数据库管理系统、软件工程、人工智能等都是十分有益的。  为什么要学习数据结构   在计算机发展的初期,人们使用计算机的目的主要是处理数值计算问题。当我们使用计算机来解决一个具体问题时,一般需要经过下列几个步骤:首先要从该具体问题抽象出一个适当的数学模型,然后设计或选择一个解此数学模型的算法,最后编出程序进行调试、测试,直至得到最终的解答。例如,求解梁架结构中应力的数学模型的线性方程组,该方程组可以使用迭代算法来求解。   由于当时所涉及的运算对象是简单的整型、实型或布尔类型数据,所以程序设计者的主要精力是集中于程序设计的技巧上,而无须重视数据结构。随着计算机应用领域的扩大和软、硬件的发展,非数值计算问题越来越显得重要。据统计,当今处理非数值计算性问题占用了90%以上的机器时间。这类问题涉及到的数据结构更为复杂,数据元素之间的相互关系一般无法用数学方程式加以描述。因此,解决这类问题的关键不再是数学分析和计算方法,而是要设计出合适的数据结构,才能有效地解决问题。下面所列举的就是属于这一类的具体问题。  例一:学生信息检索系统。当我们需要查找某个学生的有关情况的时候;或者想查询某个专业或年级的学生的有关情况的时候,只要我们建立了相关的数据结构,按照某种算法编写了相关程序,就可以实现计算机自动检索。由此,可以在学生信息检索系统中建立一张按学号顺序排列的学生信息表和分别按姓名、专业、年级顺序排列的索引表,如图1.1所示。由这四张表构成的文件便是学生信息检索的数学模型,计算机的主要操作便是按照某个特定要求(如给定姓名)对学生信息文件进行查询。  诸如此类的还有电话自动查号系统、考试查分系统、仓库库存管理系统等。在这类文档管理的数学模型中,计算机处理的对象之间通常存在着的是一种简......

阅读全文(2352) | 评论:3

数据类型和抽象数据类型(2012-02-02 00:00:00)

摘要: 摘抄
还是不太明白 首先我们回顾一下在程序设计语言中出现的各种数据类型。   数据类型   数据类型是和数据结构密切相关的一个概念。它最早出现在高级程序设计语言中,用以刻划程序中操作对象的特性。在用高级语言编写的程序中,每个变量、常量或表达式都有一个它所属的确定的数据类型。类型显式地或隐含地规定了在程序执行期间变量或表达式所有可能的取值范围,以及在这些值上允许进行的操作。因此,数据类型(Data Type)是一个值的集合和定义在这个值集上的一组操作的总称。   在高级程序设计语言中,数据类型可分为两类:一类是原子类型,另一类则是结构类型。原子类型的值是不可分解的。如C语言中整型、字符型、浮点型、双精度型等基本类型,分别用保留字int、char、float、double标识。而结构类型的值是由若干成分按某种结构组成的,因此是可分解的,并且它的成分可以是非结构的,也可以是结构的。例如,数组的值由若干分量组成,每个分量可以是整数,也可以是数组等。在某种意义上,数据结构可以看成是“一组具有相同结构的值”,而数据类型则可被看成是由一种数据结构和定义在其上的一组操作所组成的。          抽象数据类型   抽象数据类型(Abstruct Data Type,简称ADT)是指一个数学模型以及定义在该模型上的一组操作。抽象数据类型的定义取决于它的一组逻辑特性,而与其在计算机内部如何表示和实现无关。即不论其内部结构如何变化,只要它的数学特性不变,都不影响其外部的使用。   抽象数据类型和数据类型实质上是一个概念。例如,各种计算机都拥有的整数类型就是一个抽象数据类型,尽管它们在不同处理器上的实现方法可以不同,但由于其定义的数学特性相同,在用户看来都是相同的。因此,“抽象”的意义在于数据类型的数学抽象特性。   但在另一方面,抽象数据类型的范畴更广,它不再局限于前述各处理器中已定义并实现的数据类型,还包括用户在设计软件系统时自己定义的数据类型。为了提高软件的重用性,在近代程序设计方法学中,要求在构成软件系统的每个相对独立的模块上,定义一组数据和施于这些数据上的一组操作,并在模块的内部给出这些数据的表示及其操作的细节,而在模块的外部使用的只是抽象的数据及抽象的操作。这也就是面向对象的程序设计方......

阅读全文(1075) | 评论:0

Round Number 辑合(2012-02-01 23:58:00)

摘要:之一  From C-FAQ  Question 14.6 How do I round numbers?
http://c-faq.com/fp/round.html
The simplest and most straightforward way is with code like (int)(x + 0.5)C's floating to integer conversion truncates (discards) the fractional part, so adding 0.5 before truncating arranges that fractions >= 0.5 will be rounded up. (This technique won't work properly for negative numbers, though, for which you could use something like (int)(x < 0 ? x - 0.5 : x + 0.5), or play around with the floor and ceil functions.)You can round to a certain precision by scaling: (int)(x / precision + 0.5) * precision Handling negative numbers, or implementing even/odd rounding, is slightly trickier.Note that because truncation is otherwise the default, it's usually a good idea to use an explicit rounding step when converting floating-point numbers to integers. Unless you're careful, it's quite possible......

阅读全文(1131) | 评论:0

Round Or Omit(2012-02-01 23:57:00)

摘要:float aver; int sum, n; aver=sum/n;
We get the omit one.
float aver; int sum, n; aver=(float)sum/n;  //(In fact , it is ' (float)(sum) / n; ')
We get the round one.

Assign value directly -> omit int a; float b; b=3.51; a=b; print a and we get 3
And  '(int)float_number' also get the omitted one
!!! But use '%.f' we get the round one!!!  According to the C-FAQ 14.6, the simplest and most straightforward way to round number is to use this: ' (int)(x+0.5); ' However, it can be used to round number for positive numbers but not for negative ones. So a better one is: ' (int)(x<0? x-0.5 : x+0.5) '
To round to a certain precision by scaling: ' (int)(x / precision + 0.5)*precision
......

阅读全文(1178) | 评论:0

scanf()与gets()的区别(2012-02-01 23:52:00)

摘要:scanf( )函数和gets( )函数都可用于输入字符串,但在功能上有区别。若想从键盘上输入字符串"hi hello",则应该使用__gets__函数。 gets可以接收空格;而scanf遇到空格、回车和Tab键都会认为输入结束,所有它不能接收空格。 char string[15]; gets(string); /*遇到回车认为输入结束*/ scanf("%s",string); /*遇到空格认为输入结束*/ 所以在输入的字符串中包含空格时,应该使用gets输入。 scanf和gets获取字符串时的区别 在C语言中,能构获取字符串的函数至少有两个: 1.scanf() 所在头文件:stdio.h 语法:scanf("格式控制字符串",变量地址列表); 接受字符串时:scanf("%s",字符数组名或指针); 2.gets() 所在头文件:stdio.h 语法:gets(字符数组名或指针); 两者在接受字符串时: 1.不同点: scanf不能接受空格、制表符Tab、回车等; 而gets能够接受空格、制表符Tab和回车等; 2.相同点: 字符串接受结束后自动加'\0'。 例1: #include <stdio.h> main() { char ch1[10],ch2[10]; scanf("%s",ch1); gets(ch2); } 依次键入asd空格fg回车,asd空格fg回车,则ch1="asd\0",ch2="asd fg\0"。 例2: #include <stdio.h> main() { char ch1[10],ch2[10],c1,c2; scanf("%s",ch1); c1=getchar(); gets(ch2); c2=getchar(); } 依次键入asdfg回车,asdfg回车,则ch1="asdfg\0",c1='\n',ch2="asdfg\0",c2需输入。 scanf :当遇到回车,空格和tab键会自动在字符串后面添加'\0',但是回车,空格和tab键仍会留在输入的缓冲区中。 gets:可接受回车键之前输入的所有字符,并用'\n'替代 '\0'......

阅读全文(1337) | 评论:0

数据结构之顺序表和链表的比较(2012-02-01 23:49:00)

摘要: 作为线性表的两种基本的存储结构:顺序表和链表。它们在存储和操作上各有优缺点,列表比较如下:       顺序表 链表 优点 1、方法简单,各种高级语言中都有数组,容易实现; 2、不用为表示结点间的逻辑关系而增加额外的存储开销,存储密度大;3、具有按元素序号随机访问的特点,查找速度快。 1、插入、删除时,只要找到对应前驱结点,修改指针即可,无需移动元素; 2、采用动态存储分配,不会造成内存浪费和溢出。 缺点 1、插入删除操作时,需要移动元素,平均移动大约表中一半的元素,对元素较多的顺序表效率低。 2、采用静态空间分配,需要预先分配足够大的存储空间,会造成内存的浪费和溢出。 1、在有些语言中,不支持指针,不容易实现; 2、需要用额外空间存储线性表的关系,存储密度小3、不能随机访问,查找时要从头指针开始遍历。 链表的优缺点基本上与顺序表是相反。在实际应用中选取哪种存储结构应根据实际情况在存储和操作上进行权衡考虑:   1.基于存储的考虑   顺序表的存储空间是静态分配的,在程序执行之前必须明确规定它的存储规模,也就是说事先对“MAXSIZE”要有合适的设定,过大造成浪费,过小造成溢出。如果对线性表的长度或存储规模难以估计时,不宜采用顺序表;链表不用事先估计存储规模,但链表的存储密度较低(存储密度是指一个结点中数据元素所占的存储单元和整个结点所占的存储单元之比)。   2.基于操作的考虑   在顺序表中按序号访问元素的时间性能为O(1),而链表中按序号访问的时间性能是O(n),所以如果经常做的运算是按序号访问数据元素,显然顺序表优于链表;而在顺序表中做插入、删除时需移动元素,当数据元素的信息量较多且表较长时,这一点是不应忽视的;在链表中作插入、删除,虽然也要找插入位置,但主要是比较操作,从这个角度考虑显然链表较优。   3.基于开发语言的考虑   顺序表容易实现,任何高级语言中都有数组类型,链表的操作是基于指针的,有些语言不支持指针类型,并且相对指针来讲顺序表较简单。   总之,两种存储结构各有长短,选择那一种存储方式应由实际问题决定。通常“较稳定”的线性表选择顺......

阅读全文(2528) | 评论:0

c++中new和delete的使用方法(2012-02-01 23:47:00)

摘要:c++中new和delete的使用方法 new和delete运算符用于动态分配和撤销内存的运算符 new用法: 1. 开辟单变量地址空间 1)new int;  //开辟一个存放数组的存储空间,返回一个指向该存储空间的地址.int *a = new int 即为将一个int类型的地址赋值给整型指针a.  2)int *a = new int(5) 作用同上,但是同时将整数赋值为5 2.  开辟数组空间 一维: int *a = new int[100];开辟一个大小为100的整型数组空间 二维: int **a = new int[5][6] 三维及其以上:依此类推. 一般用法: new 类型 [初值] delete用法:           1. int *a = new int;                delete a;   //释放单个int的空间           2.int *a = new int[5];                delete [] a; //释放int数组空间             要访问new所开辟的结构体空间,无法直接通过变量名进行,只能通过赋值的指针进行访问.           用new和delete可以动态开辟,撤销地址空间.在编程序时,若用完一个变量(一般是暂时存储的数组),下次需要再用,但却又想省去重新初始化的功夫......

阅读全文(1048) | 评论:0

数组和指针的互换(2012-02-01 23:46:00)

摘要:由来:     我们在学习C语言的时候, 经常会写这样的程序: void Func1(int *p)
{
}
void Func2(int a[])
{
} int main()
{
  int a[10];
  Func1(a);   int *p;
  Func2(p);
}     即一维数组与指针作为函数参数的互换使用, 我们可以一眼看出这个程序是可以通过编译的.     a是数组a[10]第一个元素的地址, 作为参数传递到函数中去, 接收方是*p, 在函数中可以使用*p, 或者p[0]来访问元素. 看起来数组和指针可以这样互换着使用, 编译器会把它们编译成一样的东西.       问题的提出:     再来看下面的代码, 为什么这些代码会报错? void Func1(int (*p)[10])
{
}
void Func2(int (*p)[])
{
}
void Func3(int **p)
{
} int main()
{
  int a[10][10];
  int **p;   Func1(a); //Pass
  Func2(a); //Error1
  Func3(a); //Error2   Func1(p); //Error3
  Func2(p); //Error4
  Func3(p); //Pass
}       分析:     当把a作为参数传给函数时候, a代表的是"......

阅读全文(1728) | 评论:0

pointer底层相关(2012-02-01 23:45:00)

摘要:谭浩强1.  在程序中一般是通过变量名来对内存单元进行存取操作的。      其实程序经过编译之后已经将变量名转换为变量的地址,对变量的存取都是通过地址进行的。
2.  C语言中实参变量和形参变量之间的数据传递是单向的“值传递”方式,指针变量作函数参数也要遵循这一规则,      不可能通过调用函数来改变实参指针变量的值,但可以改变实参变量指针所指变量的值。
3.  引用数组元素可以用下标法,也可以用指针法。      使用指针法能使目标程序质量高(占内存少,运行速度快)
4.  事实上, 在编译的时候, 对数组元素a[i]就是按*(a+i)处理的, 即按数组首元素的地址加上相对位移量得到要找的元素的地址, 然后找出该单元的内容.      可看出, [ ]实际上是一种变址运算符, 将a[i]按照a+i算地址      故指向数组的指针变量也可以带下标, a[i]和*(a+i)等价
由3,4看出,引用一个数组元素, 可以:      下标法: a[i]      指针法: *(a+i) 或 *(p+i)s
只需记住一点:指针指向的数据类型与定义时指针的类型一定要是对应的。除了用强制类型转换。 ......

阅读全文(1167) | 评论:0