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: 向量和矩陣操作 [註釋]
