📄 关于fp的一些非常详细的资料.txt
字号:
衡阳市第八中学信息学奥赛论坛&zju译题站
http://61.187.179.132:82/index.asp
关于FP的一些非常详细的资料
三、TP和 FP的功能区别
1.Free Pascal理论上可以使用4GB(2^32byte)的内存,因此实际上几乎可以使用系统中的所有剩余内存(除非赛题中有内存限制),这是因为Free Pascal使用的是32位的编译器。
但是对于Turbo Pascal来说,由于是16位的编译器,因此不能定义大小超过64KB(2^16byte)的数据类型和变量,并且在DOS实模式下可以使用的内存总数只有640KB。
但这并不是说,你可以随意定义很大的数组了,因为光读入200MB的数据就会让你的程序超时了(因为现在的7200转硬盘和133的系统总线速度决定了读取数据的速度也就100MB/秒)。
2.在Free Pascal中,如果用assign给标准输入输出文件变量input和output指定了文件,在程序结束之前一定要用close关闭input和output,否则输出文件可能不能被正确的写入。
这个问题是近几年NOIP竞赛和省队训练、选拔中选手常犯的错误。尤其是程序非正常结束之前(如halt)会忘记。
3.如果用Rewrite打开文件,那么文件就只能被写入了。如果需要读取这个文件,要对文件执行Reset。所以,在Free Pascal中最好不要对一个文件同时进行读写操作。
4.在Free Pascal中,集合中的元素都是4个字节长的。
5.表达式执行的顺序是不确定的。比如对于表达式a:=g(2)+f(3); 不保证g(2)一定在f(3)之前执行。
6.函数和过程在使用时,参数的类型必须和定义时完全一致。原因是在Free Pascal中添加了函数重载功能。
7.PROTECTED,PUBLIC,PUBLISHED,TRY,FINALLY,EXCEPT,RAISE成为了关键字,因此不能作为函数和过程的名字;而FAR,NEAR不再是关键字了,原因是Free Pascal是32位系统,不再需要这些关键字。
四、FP的新增功能
1. 函数可以返回复杂的类型,比如记录和数组。如:
type arrtype=array[1..100] of longint;{必须要先定义数组基类型,否则红色部分不合法}
var i,j,k,n:longint;
a:arrtype;
function sort(a:arrtype;n:longint):arrtype;
var i,j,k:longint;
begin
for i:=1 to n-1 do
for j:=i+1 to n do
if a>a[j] then
begin
k:=a;
a:=a[j];
a[j]:=k;
end;
sort:=a;
end;
begin
read(n);
for i:=1 to n do read(a);
a:=sort(a,n);
for i:=1 to n do write(a,' ');
writeln;
end.
2.在函数中,函数的返回值可以作为一个变量来处理。比如:
function a : longint;
begin
a:=12;
while a>4 do
begin
{...}
end;
end;
这个例子在Turbo Pascal中,a>4会被认为是函数的递归调用,但是在Free Pascal中会认为a只是一个变量。如果想在Free Pascal中实现递归调用,就要写成下面的形式:
function a : longint;
begin
a:=12;
if a()>4 then { 递归调用 }
begin
{...}
end;
end;
3.exit可以接受一个参数作为函数的返回值。比如:
function a : longint;
begin
a:=12;
if a>4 then
begin
exit(a*67); { 函数的返回值就是a*67 }
end;
end;
4.Free Pascal支持函数重载。可以用相同的名字定义不同的函数,只要这些函数的参数不同,就是不同的函数。比如:
procedure DoSomething (a : longint);
begin
{...}
end;
procedure DoSomething (a : real);
begin
{...}
end;
可以使用不同的参数类型longint或者real来调用不同的DoSomething过程。
由于这个功能,函数的提前声明必须有完整的参数声明:
procedure x (v : longint); forward;
{...}
procedure x;{这里定义的过程x重载了前面声明的过程x。因此的两个x是不同的}
begin
{...}
end;
5.Free Pascal容许运算符重载。比如,可以自己为矩阵运算定义一个“+”运算。
格式: operator 运算符 (运算数) 结果
例: operator +(x:datatype; y:datatype) z:datatype;
begin
……
end;
6. Turbo Pascal中定义了十六进制数的表示方法,即在十六进制数前添加符号$,如:
X:=$F0A;
Writeln(‘X=’,x);
输出结果是X=3850。
这种进制数的表述给编程者带来很多便捷,而Free Pascal扩容了此优点,除十六进制数外,二进制数也有类似的表述(添加符号%),如:
X:=%101;
Writeln(‘X=’,x);
输出结果是X=5。
7.Turbo Pascal中注释部分可用(*comment*)或者{comment}表示,如:
Var I:integer;
Begin
(*for I:=1 to 100 do
write(i);*)
writeln(‘$’);
End.
或者:
Var I:integer;
Begin
{for I:=1 to 100 do
write(i)}
writeln(‘$’);
End.
Free Pascal除前面两种表述方法外,//comment也可以,但其中comment必须在同一行内,如:
将3、4行都括为注释部分:
Var I:integer;
Begin
//for I:=1 to 100 do
// write(i);
writeln(‘$’);
End.
只将第3行括为注释部分:
Var I:integer;
Begin
//for I:=1 to 100 do
write(i);
writeln(‘$’);
End.
8.在Free Pascal中,编译时使用 Fpc –Op3 *.pas (针对 PⅡ以上的处理器进行了优化)。但实际比赛一般没有什么用(区别不大)。
9.利用指针实现动态开辟数组
var a:^longint;
n,i:longint;
begin
readln(n);
getmem(a,sizeof(longint)*n);
for I:=1 to n do a[I]:=I;
freemem(a);
end.
实际很少用,因为一般NOIP的比赛对空间没有限制,在程序开始时总是把数组定义的足够大。
10.强制类型转换
格式:数据类型(数据)
例如:var m:longint;
n:extended;
begin
m:=123456;
n:=extended(m);
writeln(n:0:6);
end.
注意:并不是任意两个基本数据类型之间都能进行强制转换。一般来说,fp允许两个整型之间的强制转换(实际意义不大,因为在赋值时fp会自动进行整型之间的类型转换),但需注意数据范围,例如,把p定义为integer,语句p:=integer(123456)虽然编译可以通过,但执行过程中p会溢出。fp也允许整型转换为实型,但有可能带来精度误差。至于实型转整型,需要满足整型所占字节数不小于实型,如double占8个字节,因此只能转换为int64。但实型转换为整型后,结果往往是错误的。把字符转换成整型,得到的是字符的Ascii码值,例如,writeln(longint('a'))输出的结果是97。
11.乘方x^y可以表示成x**y。
注意:
A、在x是实数但y是整数的时候是不能这样表示,其他都可以,但精度可能不符合要求。
B、x**y的结果如果是整型,不能超过longint的范围;如果是实型,不能超过extended的范围。
一般还是用换底公式(exp(y*ln(x)))来计算x^y。
12.布尔表达式不一定要全部进行计算。只要最终结果已经能够确定,FP就不再计算其它还没有计算的部分。比如布尔表达式exp1 AND exp2 AND exp3,如果已知exp1的结果是false,那么整个表达式的结果肯定是false,FP对exp2和exp3就不会再进行计算。
五、FP新增数据类型
1.整型
名称 类型 表示范围 占用字节
Int64 整数类型 -9223372036854775808 ~ 9223372036854775807=2 -1 8
Qword Int64的无符号整数类型 0 ~ 18446744073709551615=2 -1 8
Cardinal Longint(-2147483648~2147483647)的无符号长整型 0 ~ 4294967295=2 -1 4
Smallint 几乎等同于类型Integer(-32768~32767) -32768 ~ 32767=2 -1 2
注意:int64不是有序类型,所以不能作为for循环的循环变量,如:
var i:int64;
begin
for I:=1 to 100 do writeln(i);
end.
编译不能通过,但word类型(integer类型的无符号整数类型,0~65535)可以。
另外,直接给一个int64类型的变量赋值一个超过longint范围的整数是不合法的,例如:定义a为int64类型,有如下语句:a:=8000000000; 编译就通不过。类似的,以下三条语句也通不过编译:
a:=2*4000000000;
a:=800000*10000;
a:=a*8000000000;
这是因为fp在表达式的计算过程中用来存储整数的最大默认类型为longint,而不是int64。
当表达式的中间值超过longint时,fp会用实型来储存中间值,而实型是不能直接赋给整型的。
解决方法:
分成两步赋值,先执行 a:=1;然后执行a:=a*800000*10000;
需要强调的是,第二步赋值中一定要把8000000000拆成若干个不超过longint型的整数的和或乘积。
如嫌上述方法麻烦,还可以利用截尾函数trunc,代码如下:
var
tmp:double;
a:int64;
begin
tmp:=8000000000;
a:=trunc(tmp);
end.
2.实型
FP中的双精度实数类型Double,比TP中的Real精确度更高。
名称 类型 表示范围 占用字节 精度
Real 实数类型 3.4e38 处理器是16位的,则占4个字节,即Single类型;如果是32位的处理器,则占8个字节,此时范围和精度都与double一样 7-8位有效数字
Double 实数类型 1.7e308 8 15-16位有效数字
extended 实数类型 1.1e4932 10 19-20位有效数字
3.允许用户按以下方式定义枚举类型:
Type
EnumerateType=(Int,Long,Double:=100,Bool,……);
这是类似于C的定义方式,定义使得Double的值是100,而并非2;Bool的值为101,而并非3……以此类推。但Int和Long的值仍为0和1。
六、FP新增单元和函数
1、过程和函数
①过程fillbyte
声明部分:Procedure FillByte(var X;Count:longint;Value:byte);
作用:用来给头地址为X的一段连续内存空间赋值,共附Count次,每次赋一个单字节无符号整型数Value。通常用fillbyte来给元素类型为byte的数组赋初值。例如:
var
a:array[1..10] of byte;
i:longint;
begin
fillbyte(a,sizeof(a),255);
for i:=1 to 10 do write(a,' ');
writeln;
end.
输出:255 255 255 255 255 255 255 255 255 255
其中,函数sizeof(a)可以求出a数组占用的字节数。
②过程fillchar
声明部分:Procedure Fillchar (Var X;Count : Longint;Value : char or byte);
作用:和fillbyte功能相同。
③过程fillword
声明部分:Procedure Fillword (Var X;Count : Longint;Value : Word);
作用:和fillbyte相仿,也是给头地址为X的一段连续空间赋值,附Count次,但每次赋的是一个值为Value的双字节无符号整数(word类型),所以每2个字节赋一次值,而fillbyte是每一个字节就赋一次值。
例:
Var a:array[1..10] of word;
i:longint;
Begin
fillword(a,sizeof(a) div 2,32767);
for i:=1 to 10 do write(a,' ');
writeln;
End.
④过程filldword
声明部分:Procedure FillDWord (Var X;Count : Longint;Value : DWord);
作用:与fillbyte相仿。Dword意思是占用4个字节的整型,具体来讲可以是常用的longint类型。
例:
Var a:array[1..10] of longint;
i:longint;
Begin
filldword(a,sizeof(a) div 4,2147483647);
for i:=1 to 10 do write(a,' ');
writeln;
End.
⑤数组比较函数comparebyte ;
函数声明:function CompareByte(var buf1,buf2;len:longint):longint;
逐字节地比较两段连续空间的前len个数据,两段空间首地址分别为buf1和buf2。如果都相同,就返回0。如果在第k个数据上首次出现不同,则返回buf1中第k个数据减去buf2中第k个数据的差。通常用来比较两个数组。类似地,comparechar是逐字符地比较,compareword是两个字节两个字节地比较,comparedword是4个字节4个字节地比较。注意慎用comparedword,它取数比较时只取每4字节的后2字节,因此当数组中存在大于65535的整数时,返回结果有可能出错。例如a[1]=65537,b[1]=1,因为65537和1的二进制后16位是一样的,所以comparedword(a,b,1)会返回0。
2、新增单元:sysutils,以下功能要用到此单元。
① 掐时:在NOIP竞赛中,禁止使用meml掐时,可以用其它方法,如以下是学生以前的掐时方法:
var t0,t1:real;
begin
t0:=meml[$40:$6c];
……
t1:=meml[$40:$6c];
if (t1-t0)/18.2>3 then {时限3秒}
begin
……
break;
end;
end.
改成:
uses sysutils;
var t1:tdatetime;
i,j,k:longint;
begin
t1:=now;
while true do
begin
if (now-t1)*86400>3 then
begin
……
break;
end;
end;
end.
② 知道年月日,求星期。
uses sysutils;
function getday(year,month,day:word):word;
var t:tdatetime;
begin
T:=encodedate(year,month,day);
Getday:=dayofweek(t);
End;
begin
writeln(getday(2005,4,20));
end.
其中year表示年号,month表示月份,day表示日期。输出1表示Sunday,2表示Monday,以此类推。
② 获取今天的日期
uses sysutils;
var year,month,day:word;
procedure getdate(var year,month,day:word);
var t:tdatetime;
begin
t:=now;
decodedate(t,year,month,day);
end;
begin
getdate(year,month,day);
writeln(year,' ',month,' ',day);
end.
其中year表示年号,month表示月份,day表示日期。
③ 判断是否是润年
uses sysutils;
var year:word;
begin
year:=2005;
if isleapyear(year)
then writeln('Yes')
else writeln('No');
end.
其中year表示年号。
④ 将一个十进制整数转换成十六进制
uses sysutils;
var x:int64;
s:string;
begin
x:=100;
s:=IntToHex(x,5);
writeln(s);
end.
其中x是十进制数,s是存十六进制数的字符串。IntToHex的第二个参数是返回的16进制数的位数,如果此参数大于实际总位数,则在高位补'0'。
⑤ 将一个整数转换成字符串
uses sysutils;
var x:int64;
s:string;
begin
x:=987654321;
s:=IntToStr(x);
writeln(s);
end.
其中x是十进制数,s是字符串。
⑥ 将一个浮点小数转换成字符串
uses sysutils;
var s:string;
x:extended;
begin
x:=12034.05678;
s:=FloatToStr(x);
writeln(s);
end.
其中x是浮点小数,s是字符串。
3、新增单元:math,以下功能要用到此单元。
① 求K
uses math;
var k,x:extended;
n:longint;
begin
k:=5;n:=10;
x:=Ldexp(k,n);
writeln(x:0:3);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -