ADA 95教程 其他标量类型2
输出枚举变量
第59行和第60行中的语句输出当前变量的当前值,以及当前值的前置值。最后,为变量Big_Sphere输出相同的值,当您运行程序时,您将看到为每行中的第一个值输出相同的值,但是两个变量的第二个值不同。注意程序第14行到第18行中给出的四行额外代码。这些用于告诉系统如何输出枚举变量,我们将很快介绍其工作原理。
我们在上一个程序中研究的in和not in运算符可用于枚举类型变量。事实上,它们可用于所有离散类型。一定要编译并运行这个程序,在研究结果之后,看看是否可以修改程序以输出额外的枚举值。
布尔变量
Example program ------> e_c06_p3.ada
-- Chapter 6 - Program 3 with Ada.Text_IO; use Ada.Text_IO; procedure BoolVars is package Bool_IO is new Ada.Text_IO.Enumeration_IO(BOOLEAN); use Bool_IO; Correct : BOOLEAN; Maybe : BOOLEAN; Probably : BOOLEAN; begin Correct := TRUE; -- TRUE Maybe := FALSE; -- FALSE Probably := Correct or Maybe; -- TRUE Probably := Correct and Maybe; -- FALSE Probably := Correct xor Maybe; -- TRUE Probably := Correct and not Maybe; -- TRUE Probably := BOOLEAN'FIRST; -- FALSE Probably := BOOLEAN'LAST; -- TRUE if Maybe < Correct then Put("FALSE is of less value than TRUE in a BOOLEAN variable"); New_Line; end if; Put(Correct, 8); Put(Maybe, 8); New_Line; end BoolVars; -- Result of execution -- FALSE is of less value than TRUE in a BOOLEAN variable -- TRUE FALSE
名为e_c06_p3.ada的程序演示了如何使用布尔变量,它实际上是枚举变量的特例。它只是一个枚举类型,有两个可能的值,TRUE或FALSE。因为它是枚举类型,所以枚举类型可用的所有操作都可用于布尔类型,包括所有六个关系运算符、赋值运算符、属性运算符,而没有数学运算符。
逻辑运算符
布尔类型有自己的一些唯一运算符,这些运算符不适用于其他类型,它们是逻辑运算符。逻辑运算符在前面定义过,但在这里作为一个完整的列表重复。
and logical and operation or logical or operation xor exclusive or of two values not inversion of the value and then short circuit and operation or else short circuit or operation
需要指出的是,根据定义,FALSE的数值小于TRUE,而实际上,FALSE的值是0,TRUE的值是1。
该程序演示了如何在第7行和第8行的包实例化之后,在第29行和第30行输出布尔值。注意,Enumeration_IO库用于布尔输出,再次说明布尔是枚举类型的特例。
一定要编译和执行这个程序,看看它是否真的编译和执行所述。有朝一日,您将需要像本程序中那样显示布尔结果的能力。
整数类型的一些无用属性
Example program ------> e_c06_p4.ada
-- Chapter 6 - Program 4 with Ada.Text_IO; use Ada.Text_IO; procedure IncrInt is Index : INTEGER; begin Index := 13; Index := INTEGER'POS(Index); -- Still 13 Index := INTEGER'VAL(Index); -- Still 13 Index := INTEGER'SUCC(Index); -- Incremented to 14 Index := INTEGER'PRED(Index); -- Decremented to 13 Index := Index + 1; -- preferred method of incrementing end IncrInt; -- Result of execution -- (No output data from this program.)
说明一些无用的属性似乎很愚蠢,但名为e_c06_p4.ada的程序正是这样做的。整数变量的POS属性定义为数字本身,VAL也是数字。整数变量的SUCC是下一个数字,PRED是前一个数字。这最后两个属性对于递增或递减程序中的变量可能很有用,但良好的编程实践会禁止使用这些属性。您应该使用非常清楚且易于理解的方法,将一个值添加到值中,然后将结果赋回到变量中,如程序的第17行所示。
尽管在这个时候这些都是无用的,但是当我们在本教程后面学习泛型时,这一点是非常有用的。
编译并运行这个程序,添加一些输出以获得一些自己的编程经验。
模块型变量
Example program ------> e_c06_p5.ada
-- Chapter 6 - Program 5 with Ada.Text_IO; use Ada.Text_IO; procedure Modular is type DIAL_RANGE is mod 5; Dial : DIAL_RANGE := 3; type MY_BINARY_BIT is mod 2; My_Bit : MY_BINARY_BIT := 1; type MY_UNSIGNED_SHORT_INT is mod 65536; type MY_UNSIGNED_BYTE is mod 256; package Mod_IO is new Ada.Text_IO.Modular_IO(DIAL_RANGE); use Mod_IO; package Bit_IO is new Ada.Text_IO.Modular_IO(MY_BINARY_BIT); use Bit_IO; begin for Index in 1..6 loop Dial := Dial + 1; Put("The value of Dial is "); Put(Dial); Put(", and the binary bit is "); Put(My_Bit); My_Bit := My_Bit + 1; -- My_Bit := My_Bit + 2; -- Error, 2 is too big to add to My_Bit New_Line; end loop; New_Line; for Index in 1..6 loop Dial := Dial - 1; Put("The value of Dial is "); Put(Dial); Put(", and the binary bit is "); Put(My_Bit); My_Bit := My_Bit - 1; New_Line; end loop; end Modular; -- Result of execution -- --- The value of Dial is 4, and the binary bit is 1 --- The value of Dial is 0, and the binary bit is 0 --- The value of Dial is 1, and the binary bit is 1 --- The value of Dial is 2, and the binary bit is 0 --- The value of Dial is 3, and the binary bit is 1 --- The value of Dial is 4, and the binary bit is 0 --- The value of Dial is 3, and the binary bit is 1 --- The value of Dial is 2, and the binary bit is 0 --- The value of Dial is 1, and the binary bit is 1 --- The value of Dial is 0, and the binary bit is 0 --- The value of Dial is 4, and the binary bit is 1 --- The value of Dial is 3, and the binary bit is 0
ada95在语言中引入了一种新的类型,模块化类型变量,它在某些程序中非常有用。在第7行中,我们将类型DIAL_RANGE定义为mod 5,这意味着任何声明为该类型的变量在达到值5时都将“模化”。第8行中声明的变量,即Dial,只能存储0到4之间的值,当它增加到超过4时,它的模回到零,没有溢出的错误指示。从0到4的任何值都可以加到它上面,也可以从中减去,它将在允许范围的上限或下限进行模运算。模变量不能存储负数。它本质上是一个无符号整数,添加了不能上溢或下溢的规定。
第10行中声明的类型是另一个mod变量MY_BINARY_BIT,它只允许存储0或1的值,而第11行中声明了一个类型为MY_BIT的变量。
在第13行和第14行中定义了另外两种类型以供说明,但在本程序中没有实际使用。
在第16行到第20行中,我们实例化了这些变量类型的模输出包,并在主程序中使用它们。我们使用递增循环和递减循环来说明这两种新类型的溢出和下溢。该计划应该是非常容易让你遵循和理解,所以没有更多的需要说。
有一些预定义的模块化类型可用,如UNSIGNED_8、UNSIGNED_16和UNSIGNED_32。它们与若干位and、or、xor等操作以及若干移位和旋转子程序一起定义在包接口中。
浮点变量
Example program ------> e_c06_p7.ada
-- Chapter 6 - Program 7 with Ada.Text_IO; use Ada.Text_IO; procedure FloatVar is PI : constant := 3.1416; TWO_PI : constant := 2 * PI; R : FLOAT; type MY_FLOAT is digits 7; type MY_LONG_FLOAT is digits 15; Area : MY_FLOAT := 2.345_12e4; -- This is 23451.2 Length : MY_FLOAT := 25.123; Factor : MY_FLOAT := 8.89; Cover : MY_LONG_FLOAT; What : BOOLEAN; Index : INTEGER := 4; package Int_IO is new Ada.Text_IO.Integer_IO(INTEGER); use Int_IO; package Flt_IO is new Ada.Text_IO.Float_IO(MY_FLOAT); use Flt_IO; begin -- Arithmetic float operations Area := Length + Factor + 12.56; Area := Length - Factor - 12.56; Area := Length * Factor * 2#111.0#; -- this is decimal 7.0 Area := Length / Factor; Area := Length ** 3; Area := Length ** (-3); Area := Length ** Index; -- Arithmetic logical compares What := Length = Factor; What := Length /= Factor; What := Length > Factor; What := Length >= Factor; What := Length < Factor; What := Length <= Factor; Area := 0.0031 + (0.027_3 * TWO_PI) / (Length ** (-Index/2)); Cover := 27.3 * TWO_PI * MY_LONG_FLOAT(Area); Put("Area is now "); Put(Area); Put(Area,5); New_Line; Put("Area is now "); Put(Area,5,5); Put(Area,5,5,0); New_Line; Put("MY_FLOAT'DIGITS = "); Put(MY_FLOAT'DIGITS); New_Line; Put("MY_FLOAT'BASE'FIRST = "); Put(MY_FLOAT'BASE'FIRST); New_Line; Put("MY_FLOAT'BASE'LAST = "); Put(MY_FLOAT'BASE'LAST); New_Line; end FloatVar; -- Result of execution -- Area is now 1.082677E+02 1.082677E+02 -- Area is now 1.08268E+02 108.26771 -- MY_FLOAT'DIGITS = 7 -- MY_FLOAT'BASE'FIRST = -1.797693E+308 -- MY_FLOAT'BASE'LAST = 1.797693E+308
检查名为e_c06_p7.ada的程序,以获取几乎所有可能的浮点数操作的示例。
在第7行和第8行中,我们首先定义两个常量,第二个常量用第一个常量来定义。请记住,Ada程序中使用的任何东西都必须事先定义,并且您将知道用其他值定义值的所有规则。这两个常量的类型是universal_real,因此它们可以用于我们将在本程序中遇到的各种实类型中的任何一种。我们在第10行声明了一个名为R的FLOAT类型的变量,它是由编译器编写器定义的,然后声明了两种新类型的浮点数,最后声明了六个不同类型的变量。
ARM将另外两种浮点类型SHORT_U FLOAT和LONG_U FLOAT定义为可选类型,编译器可能提供这两种类型。您可以通过检查编译器提供的文档或声明这些类型的变量来确定编译器是否接受声明。如果它们确实存在,您可以使用下面定义的属性来确定它们的限制。您还可以通过研究每个ADA95编译器都需要提供的附录M来确定它们的限制。附件M载有所有依赖实施的实体的定义。
如何声明新的浮点类型
第12行中使用的保留字数字告诉编译器,您不关心它用来定义数字的存储字节数,但它必须为MY_FLOAT类型的每个变量至少存储7个有效数字。第13行要求MY_ LONG_FLOAT类型的每个变量至少有15个有效数字。另一方面,第10行中使用的类型FLOAT只要求它是一个浮点数,编译器编写器可以选择使用任意多的有效数字来实现这种类型的变量。如果您编写的程序在一个编译器中运行良好,则可能无法在另一个编译器中正常运行,这可能是因为新的编译器没有使用足够的有效数字,也可能是因为新的编译器使用了更多的有效数字,从而导致程序的存储空间不足或运行太慢。因此,出于可移植性的目的,第12行和第13行中的表单是首选的。在本教程的下一章中,我们将详细介绍如何声明浮点类型。
浮点文字
定义浮点数的区别特征是使用小数点。Ada要求所有浮点文字中的小数点前后至少有一个数字,尽管其中一个或两个数字都可以是零。允许使用单个嵌入下划线来提高可读性,但不能与小数点相邻。下划线被编译器忽略,没有意义。从2到16的任何基数都可以通过先给出基数,然后用磅(#)字符括起数字来使用。基数10是默认值,无需指定。可以使用指数表示法,指数的基数与基数相同。程序的第31行演示了二进制浮点文字,您可以看到基数与整数类文字的基数相似。
浮点数学运算符
第29行到第35行说明了浮点变量可用的数学运算符,除指数运算符外,这些运算符应该是自解释的。这只能使用整数类型的指数,但它可以是正的或负的。当然,零也是允许的。
所有六个逻辑比较都可以使用浮点变量,如第38行到第43行所示。请记住,在任何语言中比较两个浮点数是否相等都是不好的做法,但是可以在Ada中进行。接下来的两行45和46说明了一些多重数学运算。
与所有变量一样,所有数学和逻辑运算中的类型必须一致,结果必须分配给正确的变量类型,否则将在编译时生成类型错误。在第46行中,由于可变区域的类型不同,因此在将其指定为覆盖区域之前,必须对其进行类型转换。整个语句将作为MY_LONG_FLOAT类型进行计算,因为这将是最终结果。在乘法之前,常数27.3和常数2π将自动从泛实到长浮点。
现在输出一些浮点值
在第22行到第25行中,我们实例化了Integer\u IO包和Float\u IO包的副本,用于Integer和MY_Float类型,并在第49行到第55行中使用它。变量区域将在第49行以默认指数表示法输出,但在第50行小数点之前有5位数字。第54行添加了一个额外的5,这将导致在小数点后输出5位数字,第四个字段(在本例中为零)将导致使用零指数或无指数表示法写入输出。
浮点属性
浮点变量和类型与有关可供使用的属性的标量类型没有区别,只是有不同的属性可用。第58到66行说明了一些可用属性的使用。名为DIGITS的属性提供特定类型可用的有效位数,返回的是通用universal_integer整数类型。
名为SMALL和LARGE的属性给出了相应类型可用的最小和最大的数字,名为FIRST和LAST的属性与BASE属性组合在一起,如第62行和第65行所示,定义了实际用户类型的基础BASE类型所使用的极值。所有这四个属性都返回一个universal_real类型的值,并显示在监视器上供您参考。请注意,浮点类型还有其他可用的属性,但目前仅详细介绍这些属性。
关于属性的更多信息,见ARM的附录K。本附录列出了Ada系统可用的所有属性。
编译并运行这个程序并观察输出。当与浮点数一起使用时,实际输出是Put过程最清晰的描述。研究属性输出的结果,然后继续下一个示例程序。
不动点变量
Example program ------> e_c06_p8.ada
-- Chapter 6 - Program 8
with Ada.Text_IO;
use Ada.Text_IO;
procedure Fixed is
COARSE_PI : constant := 3.15;
type MY_FIXED is delta 0.1 range -40.0..120.0;
type ANGLE is delta 0.05 range -COARSE_PI..COARSE_PI;
Theta, Omega, Phi : ANGLE := 0.50;
Funny_Value : MY_FIXED;
package Int_IO is new Ada.Text_IO.Integer_IO(INTEGER);
use Int_IO;
package Fix_IO is new Ada.Text_IO.Fixed_IO(MY_FIXED);
use Fix_IO;
package Fix2_IO is new Ada.Text_IO.Fixed_IO(ANGLE);
use Fix2_IO;
package Flt_IO is new Ada.Text_IO.Float_IO(FLOAT);
use Flt_IO;
begin
Put("Theta starts off with the value");
Put(Theta, 5, 2, 0);
New_Line(2);
Theta := Omega + Phi;
Theta := Omega - Phi;
Theta := 5 * Omega - 2 * Phi;
Theta := ANGLE(Omega * Phi);
Theta := ANGLE(3 * Omega / Phi);
Theta := abs(Omega - 3 * Phi);
Funny_Value := 5.1;
for Index in 1..10 loop
Put("Funny_Value is now");
Put(Funny_Value, 5, 1, 0);
Put(Funny_Value, 5, 5, 0);
Funny_Value := MY_FIXED(Funny_Value * MY_FIXED(1.1));
New_Line;
end loop;
New_Line;
Put("MY_FIXED'DELTA = ");
Put(MY_FIXED(MY_FIXED'DELTA));
New_Line;
Put("MY_FIXED'FIRST = ");
Put(MY_FIXED'FIRST);
New_Line;
Put("MY_FIXED'LAST = ");
Put(MY_FIXED'LAST);
New_Line;
end Fixed;
-- Result of execution
-- Theta starts off with the value 0.50
--
-- Funny_Value is now 5.1 5.10156
-- Funny_Value is now 5.6 5.61719
-- Funny_Value is now 6.2 6.18750
-- Funny_Value is now 6.8 6.81250
-- Funny_Value is now 7.5 7.50391
-- Funny_Value is now 8.3 8.26562
-- Funny_Value is now 9.1 9.10156
-- Funny_Value is now 10.0 10.02344
-- Funny_Value is now 11.0 11.03906
-- Funny_Value is now 12.2 12.16016
--
-- MY_FIXED'DELTA = 0.1
-- MY_FIXED'FIRST = -40.0
-- MY_FIXED'LAST = 120.0
定点变量是一个相对较新的概念,可能会有点混乱,但名为e_c06_p8.ada的文件将说明几个定点变量的用法。第9行将定点类型定义为范围为-40.0到120.0,增量为0.1,这意味着此数字的变量只能具有精确到小数点后一位的值。因此,小数点前后有固定数量的数字,因此这类变量的名称。
一个固定点号总是精确的,因为它是这样定义的。对于一个定点变量,误差永远不会逐渐累积。为了完全理解不动点类型,需要完全理解数值分析,这超出了本教程的范围。之前的程序将演示如何使用这种类型,但不会试图解释为什么应该使用它。
没有预定义的定点类型,因此由程序员定义所需的每个定点类型,如第9行和第10行所示。保留字delta表示固定点类型,每个固定点类型都需要一个范围。第12行和第13行用于声明几个变量,以便在程序中使用,然后第17行到第20行实例化包Fixed_IO ,以便与我们的两个定点类型一起使用。
如何使用定点类型?
定点类型的输出使用与第27行中为浮点数据定义的格式相同的格式。当我们谈到算术运算时,我们会发现一些有趣的规则,我们只会简单地陈述,而不会试图去证明。同一固定点类型的变量可以自由增减,只要结果在规定的范围内,就像浮点类型的变量一样。允许与universal_integer类型的常量相乘,从而得到与我们开始使用的定点类型相同的结果。两个定点变量的相乘会产生一个匿名类型,必须显式转换为某个预定义的类型,如第33行和第34行所示。固定类型的唯一可用操作器是abs操作器。
定点类型有许多属性可用,其中一些属性在第46行到第55行中进行了说明。名为DELTA、SMALL和LARGE的属性都返回一个类型为universal_real的值,必须通过类型转换将其转换为users fixed type,然后才能在程序中使用结果。第48行说明了Put过程调用中的转换。
一定要编译和运行这个程序,并观察输出,看看它是否符合您认为它应该做的基于前面的讨论。请注意,由于编译器默认值不同,编译器可能不会生成与执行结果中列出的输出相同的输出。
另一种新类型
Example program ------> e_c06_p9.ada
-- Chapter 6 - Program 9 with Ada.Text_IO; use Ada.Text_IO; procedure Decimal is type DOLLAR is delta 0.01 digits 8 range 0.00..1_000.00; type DIMES is delta 0.1 digits 6; Amount : DOLLAR := 3.00; Coins : DIMES := 1.20; package Dec_IO is new Ada.Text_IO.Decimal_IO(DOLLAR); use Dec_IO; package Dime_IO is new Ada.Text_IO.Decimal_IO(DIMES); use Dime_IO; begin for Index in 1..8 loop Amount := Amount + 1.23; Put(Amount); Coins := Coins + 3.70; Put(Coins); New_Line; end loop; end Decimal; -- Result of execution -- -- 4.23 4.9 -- 5.46 8.6 -- 6.69 12.3 -- 7.92 16.0 -- 9.15 19.7 -- 10.38 23.4 -- 11.61 27.1 -- 12.84 30.8
随着ADA96(十进制类型)的引入,语言中增加了一个新的类型。它的外观和行为非常类似于任何其他固定类型,但有一个额外的限制,即它只能使用10次方的delta。使用固定类型可以完成的每件事都可以使用decimal类型完成,并且固定类型的所有限制也应用于decimal类型。
decimal类型用于金融软件,它比固定类型有一个优点,即预定义的包名为Ada.Text_IO.Editing,这是可选信息系统附件的一部分。此软件包提供了使用美元符号、逗号和正确放置小数点的格式货币值。示例程序说明了十进制类型的使用,但没有说明可选附件的使用,因为预计只有少数面向银行业和金融业的Ada编译器支持它。
混合各种类型
Example program ------> e_c06_p10.ada
-- Chapter 6 - Program 10 with Ada.Text_IO; use Ada.Text_IO; procedure MixTypes is PI : constant := 3.1416; TWO_PI : constant := 2 * PI; type MY_FLOAT is digits 7; Size : MY_FLOAT; type MY_FIXED is delta 0.1 range -40.0..120.0; Temperature : MY_FIXED; Index : INTEGER; begin Size := TWO_PI; Temperature := 2 * TWO_PI; Temperature := 3 * Temperature; Temperature := MY_FIXED(12.0 * TWO_PI); Size := MY_FLOAT(Temperature) + PI; Size := MY_FLOAT(Temperature + PI); Index := INTEGER(Size + MY_FLOAT(Temperature) + PI); Index := INTEGER(Size) + INTEGER(Temperature) + INTEGER(PI); Index := INTEGER(Size + PI) + INTEGER(Temperature); end MixTypes; -- Result of execution -- (No output from this program.)
检查名为e_c06_p10.ada的程序,以获取将各种类型一起使用的示例。这是一个如何结合Ada中可用的各种类型的例子。本程序中的显式转换说明了许多类型转换,应该很容易理解。特别注意,第27行、第28行和第29行的最终结果不一定相同,因为在计算中的不同点进行了舍入。
注意,在Ada中,从实数到整数的转换总是舍入而不是截断。两个整数值中间的值总是从零开始移动。这在Ada 95中有详细说明,但Ada 83中没有定义。
编译并执行这个程序,以确保它能正确编译。
这将是一个很好的时机,通过检查第3.5.4节和第3.5.7节来更熟悉ARM,这两节定义了整型和浮点型变量的要求。你不会完全理解它,但你会理解它足够使它成为一个有利可图的任务。
编程练习
编写一个程序来确定编译器是否提供LONG_INTEGER和SHORT_INTEGER。如果它们可用,则使用属性来确定它们的特性。(Solution)
对LONG_FLOAT和SHORT_FLOAT执行与练习1相同的操作(Solution)
尝试获取枚举变量的第一个元素的PRED,以查看得到的运行时错误类型。如果您试图直接获取它(即使用括号中的第一个值),编译器可能会发出警告,因此您可能需要将一个变量赋给第一个值并获取该变量的PRED(Solution)
---------------------------------------------------------------------------------------------------------------------------
原英文版出处:https://perso.telecom-paristech.fr/pautet/Ada95/a95list.htm
翻译(百度):博客园 一个默默的 *** 的人