Ada 编程/数学计算
Ada非常适合各种计算。你可以定义自己的定点和浮点类型,并且借助泛型包调用所有需要的数学函数。在这方面,Ada 与 Fortran 相当。本模块将向你展示如何使用它们,同时我们将创建一个简单的 RPN 计算器。
加法可以使用预定义的运算符 + 完成。该运算符为所有数字类型预定义,以下工作代码演示了它的使用
-- A.10.1: The Package Text_IO [Annotated]withAda.Text_IO;procedureNumeric_1istypeValue_Typeisdigits12range-999_999_999_999.0e999 .. 999_999_999_999.0e999;packageT_IOrenamesAda.Text_IO;packageF_IOisnewAda.Text_IO.Float_IO (Value_Type); Value_1 : Value_Type; Value_2 : Value_Type;beginT_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);endNumeric_1;
减法可以使用预定义的运算符 - 完成。以下扩展演示展示了 + 和 - 运算符的联合使用
-- A.10.1: The Package Text_IO [Annotated]withAda.Text_IO;procedureNumeric_2istypeValue_Typeisdigits12range-999_999_999_999.0e999 .. 999_999_999_999.0e999;packageT_IOrenamesAda.Text_IO;packageF_IOisnewAda.Text_IO.Float_IO (Value_Type); Value_1 : Value_Type; Value_2 : Value_Type; Result : Value_Type; Operation : Character;beginT_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);caseOperationiswhen'+' => Result := Value_1 + Value_2;when'-' => Result := Value_1 - Value_2;whenothers=> T_IO.Put_Line ("Illegal Operation.");gotoExit_Numeric_2;endcase; 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;endNumeric_2;
纯粹主义者可能会对使用 goto 感到惊讶,但有些人更喜欢在函数内部使用 goto 而不是使用多个 return 语句,因为人们对这个问题的看法差异很大。请参阅 goto 不是邪恶的 文章。
乘法可以使用预定义的运算符 * 完成。有关演示,请参阅下一章关于除法的部分。
除法可以使用预定义的运算符 /、mod、rem 完成。运算符 / 执行普通除法,mod 返回模除法,rem 返回模除法的余数。
以下扩展演示展示了 +、-、* 和 / 运算符的联合使用,以及使用四数宽堆栈存储中间结果
运算符 mod 和 rem 不在演示中,因为它们只对整数类型定义。
withAda.Text_IO;procedureNumeric_3isprocedurePop_Value;procedurePush_Value;typeValue_Typeisdigits12range-999_999_999_999.0e999 .. 999_999_999_999.0e999;typeValue_Arrayisarray(Naturalrange1 .. 4)ofValue_Type;packageT_IOrenamesAda.Text_IO;packageF_IOisnewAda.Text_IO.Float_IO (Value_Type); Values : Value_Array := (others=> 0.0); Operation : String (1 .. 40); Last : Natural;procedurePop_ValueisbeginValues (Values'First + 1 .. Values'Last) := Values (Values'First + 2 .. Values'Last) & 0.0;endPop_Value;procedurePush_ValueisbeginValues (Values'First + 1 .. Values'Last) := Values (Values'First .. Values'Last - 1);endPush_Value;beginMain_Loop:loopT_IO.Put (">"); T_IO.Get_Line (Operation, Last);ifLast = 1andthenOperation (1) = '+'thenValues (1) := Values (1) + Values (2); Pop_Value;elsifLast = 1andthenOperation (1) = '-'thenValues (1) := Values (1) + Values (2); Pop_Value;elsifLast = 1andthenOperation (1) = '*'thenValues (1) := Values (1) * Values (2); Pop_Value;elsifLast = 1andthenOperation (1) = '/'thenValues (1) := Values (1) / Values (2); Pop_Value;elsifLast = 4andthenOperation (1 .. 4) = "exit"thenexitMain_Loop;elsePush_Value; F_IO.Get (From => Operation, Item => Values (1), Last => Last);endif; Display_Loop:forIinreverseValue_Array'RangeloopF_IO.Put (Item => Values (I), Fore => F_IO.Default_Fore, Aft => F_IO.Default_Aft, Exp => 4); T_IO.New_Line;endloopDisplay_Loop;endloopMain_Loop;return;endNumeric_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 而不是字符串,这使得比较更容易。
请注意,从现在开始我们不会再复制完整的源代码了。请按照下载链接查看完整的程序。
withAda.Text_IO;withAda.Numerics.Generic_Elementary_Functions;withAda.Strings.Unbounded;procedureNumeric_4ispackageStrrenamesAda.Strings.Unbounded;packageT_IOrenamesAda.Text_IO;procedurePop_Value;procedurePush_Value;functionGet_LinereturnStr.Unbounded_String;typeValue_Typeisdigits12range-999_999_999_999.0e999 .. 999_999_999_999.0e999;typeValue_Arrayisarray(Naturalrange1 .. 4)ofValue_Type;packageF_IOisnewAda.Text_IO.Float_IO (Value_Type);packageValue_FunctionsisnewAda.Numerics.Generic_Elementary_Functions ( Value_Type);useValue_Functions;usetypeStr.Unbounded_String; Values : Value_Array := (others=> 0.0); Operation : Str.Unbounded_String; Dummy : Natural;functionGet_LinereturnStr.Unbounded_StringisBufferSize :constant:= 2000; Retval : Str.Unbounded_String := Str.Null_Unbounded_String; Item : String (1 .. BufferSize); Last : Natural;beginGet_Whole_Line :loopT_IO.Get_Line (Item => Item, Last => Last); Str.Append (Source => Retval, New_Item => Item (1 .. Last));exitGet_Whole_LinewhenLast < Item'Last;endloopGet_Whole_Line;returnRetval;endGet_Line; ...beginMain_Loop :loopT_IO.Put (">"); Operation := Get_Line; ...elsifOperation = "e"then-- insert e Push_Value; Values (1) := Ada.Numerics.e;elsifOperation = "**"orelseOperation = "^"then-- power of x^y Values (1) := Values (1) ** Values (2); Pop_Value;elsifOperation = "sqr"then-- square root Values (1) := Sqrt (Values (1));elsifOperation = "root"then-- arbritary root Values (1) := Exp (Log (Values (2)) / Values (1)); Pop_Value;elsifOperation = "ln"then-- natural logarithm Values (1) := Log (Values (1));elsifOperation = "log"then-- based logarithm Values (1) := Log (Base => Values (1), X => Values (2)); Pop_Value;elsifOperation = "exit"thenexitMain_Loop;elsePush_Value; F_IO.Get (From => Str.To_String (Operation), Item => Values (1), Last => Dummy);endif; ...endloopMain_Loop;return;endNumeric_4;
高等数学
[edit | edit source]三角 计算
[edit | edit source]一整套 三角函数 定义在泛型包 Ada.Numerics.Generic_Elementary_Functions 中。所有函数都针对 2π 和任意循环值(一次完整的旋转周期)定义。
请注意调用 Arctan () 函数的不同之处。
withAda.Text_IO;withAda.Numerics.Generic_Elementary_Functions;withAda.Strings.Unbounded;procedureNumeric_5is...procedurePut_Line (Value :inValue_Type);useValue_Functions;usetypeStr.Unbounded_String; Values : Value_Array := (others=> 0.0); Cycle : Value_Type := Ada.Numerics.Pi; Operation : Str.Unbounded_String; Dummy : Natural; ...procedurePut_Line (Value :inValue_Type)isbeginifabsValue_Type'Exponent (Value) >=absValue_Type'Exponent (10.0 ** F_IO.Default_Aft)thenF_IO.Put (Item => Value, Fore => F_IO.Default_Aft, Aft => F_IO.Default_Aft, Exp => 4);elseF_IO.Put (Item => Value, Fore => F_IO.Default_Aft, Aft => F_IO.Default_Aft, Exp => 0);endif; T_IO.New_Line;return;endPut_Line; ...beginMain_Loop :loopDisplay_Loop :forIinreverseValue_Array'RangeloopPut_Line (Values (I));endloopDisplay_Loop; T_IO.Put (">"); Operation := Get_Line; ...elsifOperation = "deg"then-- switch to degrees Cycle := 360.0;elsifOperation = "rad"then-- switch to degrees Cycle := Ada.Numerics.Pi;elsifOperation = "grad"then-- switch to degrees Cycle := 400.0;elsifOperation = "pi"orelseOperation = "π"then-- switch to degrees Push_Value; Values (1) := Ada.Numerics.Pi;elsifOperation = "sin"then-- sinus Values (1) := Sin (X => Values (1), Cycle => Cycle);elsifOperation = "cos"then-- cosinus Values (1) := Cos (X => Values (1), Cycle => Cycle);elsifOperation = "tan"then-- tangents Values (1) := Tan (X => Values (1), Cycle => Cycle);elsifOperation = "cot"then-- cotanents Values (1) := Cot (X => Values (1), Cycle => Cycle);elsifOperation = "asin"then-- arc-sinus Values (1) := Arcsin (X => Values (1), Cycle => Cycle);elsifOperation = "acos"then-- arc-cosinus Values (1) := Arccos (X => Values (1), Cycle => Cycle);elsifOperation = "atan"then-- arc-tangents Values (1) := Arctan (Y => Values (1), Cycle => Cycle);elsifOperation = "acot"then-- arc-cotanents Values (1) := Arccot (X => Values (1), Cycle => Cycle); ...endloopMain_Loop;return;endNumeric_5;
该演示还包含改进的数字输出,其行为更像普通计算器。
双曲 计算
[edit | edit source]你猜对了:一整套双曲函数定义在泛型包 Ada.Numerics.Generic_Elementary_Functions 中。
withAda.Text_IO;withAda.Numerics.Generic_Elementary_Functions;withAda.Strings.Unbounded;withAda.Exceptions;procedureNumeric_6ispackageStrrenamesAda.Strings.Unbounded;packageT_IOrenamesAda.Text_IO;packageExeptrenamesAda.Exceptions; ...beginMain_Loop :loopTry :beginDisplay_Loop : ...elsifOperation = "sinh"then-- sinus hyperbolic Values (1) := Sinh (Values (1));elsifOperation = "cosh"then-- cosinus hyperbolic Values (1) := Coth (Values (1));elsifOperation = "tanh"then-- tangents hyperbolic Values (1) := Tanh (Values (1));elsifOperation = "coth"then-- cotanents hyperbolic Values (1) := Coth (Values (1));elsifOperation = "asinh"then-- arc-sinus hyperbolic Values (1) := Arcsinh (Values (1));elsifOperation = "acosh"then-- arc-cosinus hyperbolic Values (1) := Arccosh (Values (1));elsifOperation = "atanh"then-- arc-tangents hyperbolic Values (1) := Arctanh (Values (1));elsifOperation = "acoth"then-- arc-cotanents hyperbolic Values (1) := Arccoth (Values (1)); ...exceptionwhenAn_Exception :others=> T_IO.Put_Line (Exept.Exception_Information (An_Exception));endTry;endloopMain_Loop;return;endNumeric_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 ()函数具有很强的容错性 - 即使忘记 "," 或 "()" 对,它也能正确解析输入。
因此,只需进行一些修改,就可以将 "正常" 计算器转换为复数运算计算器。
withAda.Text_IO.Complex_IO;withAda.Numerics.Generic_Complex_Types;withAda.Numerics.Generic_Complex_Elementary_Functions;withAda.Strings.Unbounded;withAda.Exceptions;procedureNumeric_7is...packageComplex_TypesisnewAda.Numerics.Generic_Complex_Types ( Value_Type);packageComplex_FunctionsisnewAda.Numerics.Generic_Complex_Elementary_Functions ( Complex_Types);packageC_IOisnewAda.Text_IO.Complex_IO (Complex_Types);typeValue_Arrayisarray(Naturalrange1 .. 4)ofComplex_Types.Complex;procedurePut_Line (Value :inComplex_Types.Complex);usetypeComplex_Types.Complex;usetypeStr.Unbounded_String;useComplex_Functions; Values : Value_Array := (others=> Complex_Types.Complex'(Re => 0.0, Im => 0.0)); ...procedurePut_Line (Value :inComplex_Types.Complex)isbeginif(absValue_Type'Exponent (Value.Re) >=absValue_Type'Exponent (10.0 ** C_IO.Default_Aft))orelse(absValue_Type'Exponent (Value.Im) >=absValue_Type'Exponent (10.0 ** C_IO.Default_Aft))thenC_IO.Put (Item => Value, Fore => C_IO.Default_Aft, Aft => C_IO.Default_Aft, Exp => 4);elseC_IO.Put (Item => Value, Fore => C_IO.Default_Aft, Aft => C_IO.Default_Aft, Exp => 0);endif; T_IO.New_Line;return;endPut_Line;begin...elsifOperation = "e"then-- insert e Push_Value; Values (1) := Complex_Types.Complex'(Re => Ada.Numerics.e, Im => 0.0); ...elsifOperation = "pi"orelseOperation = "π"then-- insert pi Push_Value; Values (1) := Complex_Types.Complex'(Re => Ada.Numerics.Pi, Im => 0.0);elsifOperation = "sin"then-- sinus Values (1) := Sin (Values (1));elsifOperation = "cos"then-- cosinus Values (1) := Cot (Values (1));elsifOperation = "tan"then-- tangents Values (1) := Tan (Values (1));elsifOperation = "cot"then-- cotanents Values (1) := Cot (Values (1));elsifOperation = "asin"then-- arc-sinus Values (1) := Arcsin (Values (1));elsifOperation = "acos"then-- arc-cosinus Values (1) := Arccos (Values (1));elsifOperation = "atan"then-- arc-tangents Values (1) := Arctan (Values (1));elsifOperation = "acot"then-- arc-cotanents Values (1) := Arccot (Values (1)); ...return;endNumeric_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: 向量和矩阵操作 [注释]
