Ada 编程/数学计算
Ada非常适合各种计算。你可以定义自己的定点和浮点类型,并且借助泛型包调用所有需要的数学函数。在这方面,Ada 与 Fortran 相当。本模块将向你展示如何使用它们,同时我们将创建一个简单的 RPN 计算器。
加法可以使用预定义的运算符 + 完成。该运算符为所有数字类型预定义,以下工作代码演示了它的使用
-- A.10.1: The Package Text_IO [Annotated]with
Ada.Text_IO;procedure
Numeric_1is
type
Value_Typeis
digits
12range
-999_999_999_999.0e999 .. 999_999_999_999.0e999;package
T_IOrenames
Ada.Text_IO;package
F_IOis
new
Ada.Text_IO.Float_IO (Value_Type); Value_1 : Value_Type; Value_2 : Value_Type;begin
T_IO.Put ("First Value : "); F_IO.Get (Value_1); T_IO.Put ("Second Value : "); F_IO.Get (Value_2); F_IO.Put (Value_1); T_IO.Put (" + "); F_IO.Put (Value_2); T_IO.Put (" = "); F_IO.Put (Value_1 + Value_2);end
Numeric_1;
减法可以使用预定义的运算符 - 完成。以下扩展演示展示了 + 和 - 运算符的联合使用
-- A.10.1: The Package Text_IO [Annotated]with
Ada.Text_IO;procedure
Numeric_2is
type
Value_Typeis
digits
12range
-999_999_999_999.0e999 .. 999_999_999_999.0e999;package
T_IOrenames
Ada.Text_IO;package
F_IOis
new
Ada.Text_IO.Float_IO (Value_Type); Value_1 : Value_Type; Value_2 : Value_Type; Result : Value_Type; Operation : Character;begin
T_IO.Put ("First Value : "); F_IO.Get (Value_1); T_IO.Put ("Second Value : "); F_IO.Get (Value_2); T_IO.Put ("Operation : "); T_IO.Get (Operation);case
Operationis
when
'+' => Result := Value_1 + Value_2;when
'-' => Result := Value_1 - Value_2;when
others
=> T_IO.Put_Line ("Illegal Operation.");goto
Exit_Numeric_2;end
case
; F_IO.Put (Value_1); T_IO.Put (" "); T_IO.Put (Operation); T_IO.Put (" "); F_IO.Put (Value_2); T_IO.Put (" = "); F_IO.Put (Result); <<Exit_Numeric_2>>return
;end
Numeric_2;
纯粹主义者可能会对使用 goto 感到惊讶,但有些人更喜欢在函数内部使用 goto 而不是使用多个 return 语句,因为人们对这个问题的看法差异很大。请参阅 goto 不是邪恶的 文章。
乘法可以使用预定义的运算符 * 完成。有关演示,请参阅下一章关于除法的部分。
除法可以使用预定义的运算符 /、mod、rem 完成。运算符 / 执行普通除法,mod 返回模除法,rem 返回模除法的余数。
以下扩展演示展示了 +、-、* 和 / 运算符的联合使用,以及使用四数宽堆栈存储中间结果
运算符 mod 和 rem 不在演示中,因为它们只对整数类型定义。
with
Ada.Text_IO;procedure
Numeric_3is
procedure
Pop_Value;procedure
Push_Value;type
Value_Typeis
digits
12range
-999_999_999_999.0e999 .. 999_999_999_999.0e999;type
Value_Arrayis
array
(Naturalrange
1 .. 4)of
Value_Type;package
T_IOrenames
Ada.Text_IO;package
F_IOis
new
Ada.Text_IO.Float_IO (Value_Type); Values : Value_Array := (others
=> 0.0); Operation : String (1 .. 40); Last : Natural;procedure
Pop_Valueis
begin
Values (Values'First + 1 .. Values'Last) := Values (Values'First + 2 .. Values'Last) & 0.0;end
Pop_Value;procedure
Push_Valueis
begin
Values (Values'First + 1 .. Values'Last) := Values (Values'First .. Values'Last - 1);end
Push_Value;begin
Main_Loop:loop
T_IO.Put (">"); T_IO.Get_Line (Operation, Last);if
Last = 1and
then
Operation (1) = '+'then
Values (1) := Values (1) + Values (2); Pop_Value;elsif
Last = 1and
then
Operation (1) = '-'then
Values (1) := Values (1) + Values (2); Pop_Value;elsif
Last = 1and
then
Operation (1) = '*'then
Values (1) := Values (1) * Values (2); Pop_Value;elsif
Last = 1and
then
Operation (1) = '/'then
Values (1) := Values (1) / Values (2); Pop_Value;elsif
Last = 4and
then
Operation (1 .. 4) = "exit"then
exit
Main_Loop;else
Push_Value; F_IO.Get (From => Operation, Item => Values (1), Last => Last);end
if
; Display_Loop:for
Iin
reverse
Value_Array'Rangeloop
F_IO.Put (Item => Values (I), Fore => F_IO.Default_Fore, Aft => F_IO.Default_Aft, Exp => 4); T_IO.New_Line;end
loop
Display_Loop;end
loop
Main_Loop;return
;end
Numeric_3;
所有指数函数都在泛型包 Ada.Numerics.Generic_Elementary_Functions 中定义。
形式为 的计算由运算符 ** 执行。注意:此运算符有两个版本。预定义的运算符 ** 只允许使用 Standard.Integer 作为指数。如果你需要使用浮点类型作为指数,你需要使用 **,它定义在 Ada.Numerics.Generic_Elementary_Functions 中。
平方根 由函数 Sqrt()
计算。没有定义计算任意根 的函数。但是可以使用对数来计算任意根,使用数学恒等式: 在 Ada 中将变为 root := Exp (Log (a) / b)
。或者,使用 在 Ada 中为 root := a**(1.0/b)
。
对数
[edit | edit source]Ada.Numerics.Generic_Elementary_Functions 定义了任意对数 和自然对数 的函数,它们都具有相同的名称 Log()
,区别在于参数的数量。
演示
[edit | edit source]以下扩展演示展示了如何在 Ada 中使用指数函数。新的演示还使用 Unbounded_String 而不是字符串,这使得比较更容易。
请注意,从现在开始我们不会再复制完整的源代码了。请按照下载链接查看完整的程序。
with
Ada.Text_IO;with
Ada.Numerics.Generic_Elementary_Functions;with
Ada.Strings.Unbounded;procedure
Numeric_4is
package
Strrenames
Ada.Strings.Unbounded;package
T_IOrenames
Ada.Text_IO;procedure
Pop_Value;procedure
Push_Value;function
Get_Linereturn
Str.Unbounded_String;type
Value_Typeis
digits
12range
-999_999_999_999.0e999 .. 999_999_999_999.0e999;type
Value_Arrayis
array
(Naturalrange
1 .. 4)of
Value_Type;package
F_IOis
new
Ada.Text_IO.Float_IO (Value_Type);package
Value_Functionsis
new
Ada.Numerics.Generic_Elementary_Functions ( Value_Type);use
Value_Functions;use
type
Str.Unbounded_String; Values : Value_Array := (others
=> 0.0); Operation : Str.Unbounded_String; Dummy : Natural;function
Get_Linereturn
Str.Unbounded_Stringis
BufferSize :constant
:= 2000; Retval : Str.Unbounded_String := Str.Null_Unbounded_String; Item : String (1 .. BufferSize); Last : Natural;begin
Get_Whole_Line :loop
T_IO.Get_Line (Item => Item, Last => Last); Str.Append (Source => Retval, New_Item => Item (1 .. Last));exit
Get_Whole_Linewhen
Last < Item'Last;end
loop
Get_Whole_Line;return
Retval;end
Get_Line; ...begin
Main_Loop :loop
T_IO.Put (">"); Operation := Get_Line; ...elsif
Operation = "e"then
-- insert e Push_Value; Values (1) := Ada.Numerics.e;elsif
Operation = "**"or
else
Operation = "^"then
-- power of x^y Values (1) := Values (1) ** Values (2); Pop_Value;elsif
Operation = "sqr"then
-- square root Values (1) := Sqrt (Values (1));elsif
Operation = "root"then
-- arbritary root Values (1) := Exp (Log (Values (2)) / Values (1)); Pop_Value;elsif
Operation = "ln"then
-- natural logarithm Values (1) := Log (Values (1));elsif
Operation = "log"then
-- based logarithm Values (1) := Log (Base => Values (1), X => Values (2)); Pop_Value;elsif
Operation = "exit
"then
exit
Main_Loop;else
Push_Value; F_IO.Get (From => Str.To_String (Operation), Item => Values (1), Last => Dummy);end
if
; ...end
loop
Main_Loop;return
;end
Numeric_4;
高等数学
[edit | edit source]三角 计算
[edit | edit source]一整套 三角函数 定义在泛型包 Ada.Numerics.Generic_Elementary_Functions 中。所有函数都针对 2π 和任意循环值(一次完整的旋转周期)定义。
请注意调用 Arctan ()
函数的不同之处。
with
Ada.Text_IO;with
Ada.Numerics.Generic_Elementary_Functions;with
Ada.Strings.Unbounded;procedure
Numeric_5is
...procedure
Put_Line (Value :in
Value_Type);use
Value_Functions;use
type
Str.Unbounded_String; Values : Value_Array := (others
=> 0.0); Cycle : Value_Type := Ada.Numerics.Pi; Operation : Str.Unbounded_String; Dummy : Natural; ...procedure
Put_Line (Value :in
Value_Type)is
begin
if
abs
Value_Type'Exponent (Value) >=abs
Value_Type'Exponent (10.0 ** F_IO.Default_Aft)then
F_IO.Put (Item => Value, Fore => F_IO.Default_Aft, Aft => F_IO.Default_Aft, Exp => 4);else
F_IO.Put (Item => Value, Fore => F_IO.Default_Aft, Aft => F_IO.Default_Aft, Exp => 0);end
if
; T_IO.New_Line;return
;end
Put_Line; ...begin
Main_Loop :loop
Display_Loop :for
Iin
reverse
Value_Array'Rangeloop
Put_Line (Values (I));end
loop
Display_Loop; T_IO.Put (">"); Operation := Get_Line; ...elsif
Operation = "deg"then
-- switch to degrees Cycle := 360.0;elsif
Operation = "rad"then
-- switch to degrees Cycle := Ada.Numerics.Pi;elsif
Operation = "grad"then
-- switch to degrees Cycle := 400.0;elsif
Operation = "pi"or
else
Operation = "π"then
-- switch to degrees Push_Value; Values (1) := Ada.Numerics.Pi;elsif
Operation = "sin"then
-- sinus Values (1) := Sin (X => Values (1), Cycle => Cycle);elsif
Operation = "cos"then
-- cosinus Values (1) := Cos (X => Values (1), Cycle => Cycle);elsif
Operation = "tan"then
-- tangents Values (1) := Tan (X => Values (1), Cycle => Cycle);elsif
Operation = "cot"then
-- cotanents Values (1) := Cot (X => Values (1), Cycle => Cycle);elsif
Operation = "asin"then
-- arc-sinus Values (1) := Arcsin (X => Values (1), Cycle => Cycle);elsif
Operation = "acos"then
-- arc-cosinus Values (1) := Arccos (X => Values (1), Cycle => Cycle);elsif
Operation = "atan"then
-- arc-tangents Values (1) := Arctan (Y => Values (1), Cycle => Cycle);elsif
Operation = "acot"then
-- arc-cotanents Values (1) := Arccot (X => Values (1), Cycle => Cycle); ...end
loop
Main_Loop;return
;end
Numeric_5;
该演示还包含改进的数字输出,其行为更像普通计算器。
双曲 计算
[edit | edit source]你猜对了:一整套双曲函数定义在泛型包 Ada.Numerics.Generic_Elementary_Functions 中。
with
Ada.Text_IO;with
Ada.Numerics.Generic_Elementary_Functions;with
Ada.Strings.Unbounded;with
Ada.Exceptions;procedure
Numeric_6is
package
Strrenames
Ada.Strings.Unbounded;package
T_IOrenames
Ada.Text_IO;package
Exeptrenames
Ada.Exceptions; ...begin
Main_Loop :loop
Try :begin
Display_Loop : ...elsif
Operation = "sinh"then
-- sinus hyperbolic Values (1) := Sinh (Values (1));elsif
Operation = "cosh"then
-- cosinus hyperbolic Values (1) := Coth (Values (1));elsif
Operation = "tanh"then
-- tangents hyperbolic Values (1) := Tanh (Values (1));elsif
Operation = "coth"then
-- cotanents hyperbolic Values (1) := Coth (Values (1));elsif
Operation = "asinh"then
-- arc-sinus hyperbolic Values (1) := Arcsinh (Values (1));elsif
Operation = "acosh"then
-- arc-cosinus hyperbolic Values (1) := Arccosh (Values (1));elsif
Operation = "atanh"then
-- arc-tangents hyperbolic Values (1) := Arctanh (Values (1));elsif
Operation = "acoth"then
-- arc-cotanents hyperbolic Values (1) := Arccoth (Values (1)); ...exception
when
An_Exception :others
=> T_IO.Put_Line (Exept.Exception_Information (An_Exception));end
Try;end
loop
Main_Loop;return
;end
Numeric_6;
作为额外奖励,此版本支持错误处理,因此在执行非法计算时不会直接崩溃。
复数 运算
[edit | edit source]对于 复数运算,Ada 提供了包 Ada.Numerics.Generic_Complex_Types。该包是“特殊需求附录”的一部分,这意味着它是可选的。开源 Ada 编译器 GNAT 实现了所有“特殊需求附录”,因此可以使用复数运算。
由于 Ada 支持用户自定义运算符,所有 (+, -, *) 运算符在包 Ada.Numerics.Generic_Complex_Types 被实例化 (package
... is
new
...) 并且类型被设置为可见 (use
type
...) 后,就拥有了它们通常的含义。
Ada 还提供了包 Ada.Text_IO.Complex_IO 和 Ada.Numerics.Generic_Complex_Elementary_Functions,它们提供了与普通对应项类似的功能。但是,它们之间存在一些差异。
- Ada.Numerics.Generic_Complex_Elementary_Functions 仅支持在复数运算中有效的指数和三角函数。
- Ada.Text_IO.Complex_IO 是 Ada.Text_IO 的子包,因此需要它自己的
with
。注意:Ada.Text_IO.Complex_IOGet ()
函数具有很强的容错性 - 即使忘记 "," 或 "()" 对,它也能正确解析输入。
因此,只需进行一些修改,就可以将 "正常" 计算器转换为复数运算计算器。
with
Ada.Text_IO.Complex_IO;with
Ada.Numerics.Generic_Complex_Types;with
Ada.Numerics.Generic_Complex_Elementary_Functions;with
Ada.Strings.Unbounded;with
Ada.Exceptions;procedure
Numeric_7is
...package
Complex_Typesis
new
Ada.Numerics.Generic_Complex_Types ( Value_Type);package
Complex_Functionsis
new
Ada.Numerics.Generic_Complex_Elementary_Functions ( Complex_Types);package
C_IOis
new
Ada.Text_IO.Complex_IO (Complex_Types);type
Value_Arrayis
array
(Naturalrange
1 .. 4)of
Complex_Types.Complex;procedure
Put_Line (Value :in
Complex_Types.Complex);use
type
Complex_Types.Complex;use
type
Str.Unbounded_String;use
Complex_Functions; Values : Value_Array := (others
=> Complex_Types.Complex'(Re => 0.0, Im => 0.0)); ...procedure
Put_Line (Value :in
Complex_Types.Complex)is
begin
if
(abs
Value_Type'Exponent (Value.Re) >=abs
Value_Type'Exponent (10.0 ** C_IO.Default_Aft))or
else
(abs
Value_Type'Exponent (Value.Im) >=abs
Value_Type'Exponent (10.0 ** C_IO.Default_Aft))then
C_IO.Put (Item => Value, Fore => C_IO.Default_Aft, Aft => C_IO.Default_Aft, Exp => 4);else
C_IO.Put (Item => Value, Fore => C_IO.Default_Aft, Aft => C_IO.Default_Aft, Exp => 0);end
if
; T_IO.New_Line;return
;end
Put_Line;begin
...elsif
Operation = "e"then
-- insert e Push_Value; Values (1) := Complex_Types.Complex'(Re => Ada.Numerics.e, Im => 0.0); ...elsif
Operation = "pi"or
else
Operation = "π"then
-- insert pi Push_Value; Values (1) := Complex_Types.Complex'(Re => Ada.Numerics.Pi, Im => 0.0);elsif
Operation = "sin"then
-- sinus Values (1) := Sin (Values (1));elsif
Operation = "cos"then
-- cosinus Values (1) := Cot (Values (1));elsif
Operation = "tan"then
-- tangents Values (1) := Tan (Values (1));elsif
Operation = "cot"then
-- cotanents Values (1) := Cot (Values (1));elsif
Operation = "asin"then
-- arc-sinus Values (1) := Arcsin (Values (1));elsif
Operation = "acos"then
-- arc-cosinus Values (1) := Arccos (Values (1));elsif
Operation = "atan"then
-- arc-tangents Values (1) := Arctan (Values (1));elsif
Operation = "acot"then
-- arc-cotanents Values (1) := Arccot (Values (1)); ...return
;end
Numeric_7;
Ada 支持 向量 和 矩阵 运算,适用于正常的实数类型和复数类型。对于这些类型,使用泛型包 Ada.Numerics.Generic_Real_Arrays 和 Ada.Numerics.Generic_Complex_Arrays。这两个包都提供了通常的运算集,但没有 I/O 包,并且没有用于基本函数的包。
由于没有用于向量和矩阵 I/O 的包,因此创建演示要复杂得多,因此尚未准备好。可以查看当前的进度,它将是一个合并所有功能的通用计算器。
状态:停滞 - 对于向量和矩阵堆栈,我们需要 Indefinite_Vectors - 它们目前不是 GNAT/Pro 的一部分。好吧,我可以使用 booch 组件......
- Ada 编程
- Ada 编程/分隔符/-
- Ada 编程/库/Ada.Numerics.Generic Complex Types
- Ada 编程/库/Ada.Numerics.Generic Elementary Functions
- 4.4:表达式 [带注释的]
- A.5.1:基本函数 [带注释的]
- A.10.1:Text_IO 包 [带注释的]
- G.1:复数运算 [带注释的]
- G.3:向量和矩阵操作 [带注释的]
- 4.4:表达式 [带注释的]
- A.5.1:基本函数 [带注释的]
- A.10.1:Text_IO 包 [带注释的]
- G.1:复数运算 [带注释的]
- G.3: 向量和矩阵操作 [注释]