Ada 2005 访问类型

huangapple go评论61阅读模式
英文:

Ada 2005 access type

问题

我正在尝试使用Euler方法解决微分方程,使用的技术在*《Ada软件工程师的第二版》*第13.6.1节中有所提及,从第263页开始。

我已经修改了书中给出的微分方程为dy/dx = 2xy,初始条件为y(x=1) = 1。增量为h = 0.1,我需要找出y(1),y(1.1),y(1.2),y(1.3),y(1.4)和y(1.5)的值。

有三个Ada文件:diff.adb是主文件,euler.ads和euler.adb。

diff.adb文件如下:

with Ada.Text_IO;
with Euler;
procedure Diff is

  type Real is digits 6;
  type Vector is array(Integer range <>) of Real;
  type Ptr is access function (X: Real; Y: Real) return Real;

  procedure Solve is new Euler(Real, Vector, Ptr);

  function Ident(X: Real; Y: Real) return Real is
  begin
    return 2.0*X*Y;
  end Ident;

  package Real_IO is new Ada.Text_IO.Float_IO(Real);
  use Real_IO;

  Answer: Vector(1..10);

begin
  Solve(Ident'Access, 1.0, 0.1, Answer);
  for N in Answer'Range loop
    Put(1.0 + 0.1 * Real(N-1), Exp => 0);
    Put( Answer(N), Exp => 0);
    Ada.Text_IO.New_Line;
  end loop;
end Diff;

euler.ads文件如下:

--
-- 解决微分方程。
-- 展示了通用浮点类型。
--
generic
  type Float_Type is digits <>;
  type Vector is array(Integer range <>) of Float_Type;
  type Function_Ptr is access function (X: Float_Type; Y: Float_Type) return Float_Type;
procedure Euler(
  F: in Function_Ptr; Init, H: in Float_Type; Result: out Vector);

euler.adb文件如下:

procedure Euler(
  F: in Function_Ptr; Init, H: in Float_Type; Result: out Vector) is
begin
  Result(Result'First) := Init;
  for N in Result'First+1..Result'Last loop
    Result(N) := Result(N-1) + H * F(Result(N-1));
  end loop;
end Euler;

当我编译diff.adb时,出现错误消息:

euler.adb: Builder results
euler.adb:6:36
missing argument for parameter Y

由于我不太了解访问类型,如果能帮助我使上述代码工作,我将非常感激。

英文:

I am trying to solve a differential equation with Euler's method using the technique employed with the access type shown in Ben Ari second editions of Ada for Software Engineers, Section 13.6.1 starting on Page 263.

I have modified the differential equation given in the book to dy/dx = 2xy with Initial Condition y(x=1) = 1. The increment is h = 0.1 and I have to find output the values of y(1), y(1.1), y(1.2), y(1.3), y(1.4) and y(1.5).

There are 3 Ada files: diff.adb which is the main file, euler.ads and euler.adb.

The file diff.adb is

with Ada.Text_IO;
with Euler;
procedure Diff is

  type Real is digits 6;
  type Vector is array(Integer range &lt;&gt;) of Real;
  type Ptr is access function (X: Real; Y: Real) return Real;

  procedure Solve is new Euler(Real, Vector, Ptr);

  function Ident(X: Real; Y: Real) return Real is
  begin
    return 2.0*X*Y;
  end Ident;

  package Real_IO is new Ada.Text_IO.Float_IO(Real);
  use Real_IO;

  Answer: Vector(1..10);

begin
  Solve(Ident&#39;Access, 1.0, 0.1, Answer);
  for N in Answer&#39;Range loop
    Put(1.0 + 0.1 * Real(N-1), Exp =&gt; 0);
    Put( Answer(N), Exp =&gt; 0);
    Ada.Text_IO.New_Line;
  end loop;
end Diff;


The file euler.ads is

--
-- Solving a differential equation.
-- Demonstrates generic floating point type.
--
generic
  type Float_Type is digits &lt;&gt;;
  type Vector is array(Integer range &lt;&gt;) of Float_Type;
  type Function_Ptr is access function (X: Float_Type; Y: Float_Type) return Float_Type;
procedure Euler(
  F: in Function_Ptr; Init, H: in Float_Type; Result: out Vector);

And the file euler.adb is

procedure Euler(
  F: in Function_Ptr; Init, H: in Float_Type; Result: out Vector) is
begin
  Result(Result&#39;First) := Init;
  for N in Result&#39;First+1..Result&#39;Last loop
    Result(N) := Result(N-1) + H * F(Result(N-1));
  end loop;
end Euler;

When I compile diff.adb, I get the error message:

euler.adb: Builder results
euler.adb:6:36
missing argument for parameter Y

As I don't understand access types well, I would be very grateful if I can get help making the above codes work.

PS: The results to be outputtted should be as follows when worked out by hand and a calculator:

x y
1 1
1.1 1.2
1.2 1.464
1.3 1.815360
1.4 2.287354
1.5 2.927813

The first column gives the x values (with an increment of 0.1) and the second column gives the ouput of the Euler method (y values).

After Simon's help:

I used Simon's code for euler.adb:

This was changed to Simon's code:

procedure Euler
  (F : in Function_Ptr; Init, H : in Float_Type; Result : out Vector)
is
      Step : constant Float_Type := H;
   
     Current_X : Float_Type := 1.0;
begin
   Result (Result&#39;First) := Init;
   for N in Result&#39;First + 1 .. Result&#39;Last loop
      Current_X := Current_X + Step;
      Result (N) := Result (N - 1) + Step * F (Current_X, Result (N - 1));
   end loop;
end Euler;

The initial value of X is 1.0 and it is 1.0 as well for Y. In diff.adb, the output line Put(0.1 * Real(N-1), Exp => 0) has been changed to Put(1.0 + 0.1 * Real(N-1), Exp => 0) so as to get the sequence 1.0 to 1.5 (with also the line Answer: Vector(1..6) accordingly modified from 10 to 6).

When I run the corrected code I now get:

x y
1 1.00000
1.1 1.22000
1.2 1.51280
1.3 1.90613
1.4 2.43984
1.5 3.17180

The Y values from the above table are not OK as compared with the values from the table given up earlier.
For instance by hand calculation, Y(1.1)= 1 + 0.1 * 2.0 * 1 * 1 = 1.2 where I am using the equation Y1 = Y0 + h*f(X0, Y0) with Y0 and X0 as the initial values of 1 both and h is the X increment of 0.1. Then Y(1.2) = 1.2 + 0.1 * 2 * 1.1 * 1.2 = 1.464000 where I used the equation Y2 = Y1 + h * f(X1, Y1) with X1 = X0 + h = 1 + 0.1 = 1.1 and Y1 has been calculated in the previous iteration as Y(X=1.1)=1.2. Then we can continue calculating for Y(X=1.3), Y(X=1.4) and Y(X=1.5) in a similar manner.

答案1

得分: 2

这是euler.adb的改版,至少能使你进行编译。

我强烈建议使用更有意义的变量名;H 在数学教科书(或维基百科!)中可能没问题,但对于非数学背景的维护者几乎没有帮助。另外,我使用 gnatpp 重新格式化了代码,使其更接近正常的实践。

procedure Euler
  (F : in Function_Ptr; Init, H : in Float_Type; Result : out Vector)
is
   --  为了清晰起见重新命名
   步长 : constant Float_Type := H;
   
   --  我猜 Init 是初始的 Y 值,那么 X 的初始值是什么呢?
   --  在这里进行猜测 ...
   当前_X : Float_Type := 0.0;
begin
   Result (Result'First) := Init;
   for N in Result'First + 1 .. Result'Last loop
      当前_X := 当前_X + 步长;
      Result (N) := Result (N - 1) + 步长 * F (当前_X, Result (N - 1));
   end loop;
end Euler;

结果:

X Y
0.00000 1.00000
0.10000 1.02000
0.20000 1.06080
0.30000 1.12445
0.40000 1.21440
0.50000 1.33584
0.60000 1.49615
0.70000 1.70561
0.80000 1.97850
0.90000 2.33463
英文:

This is a reworking of euler.adb, which at least gets you a compilation.

I’d strongly recommend more meaningful names; H may be OK in a maths textbook (or Wikipedia!) but it hardly helps a non-mathematical maintainer. Also, I reformatted the code (using gnatpp) to be closer to normal practice.

procedure Euler
  (F : in Function_Ptr; Init, H : in Float_Type; Result : out Vector)
is
   --  renamed for clarity
   Step : constant Float_Type := H;
   
   --  Init is the initial Y, I think, so what&#39;s the initial value of
   --  X?  guessing here ...
   Current_X : Float_Type := 0.0;
begin
   Result (Result&#39;First) := Init;
   for N in Result&#39;First + 1 .. Result&#39;Last loop
      Current_X := Current_X + Step;
      Result (N) := Result (N - 1) + Step * F (Current_X, Result (N - 1));
   end loop;
end Euler;

Results:

X Y
0.00000 1.00000
0.10000 1.02000
0.20000 1.06080
0.30000 1.12445
0.40000 1.21440
0.50000 1.33584
0.60000 1.49615
0.70000 1.70561
0.80000 1.97850
0.90000 2.33463

答案2

得分: 1

你的函数接受两个参数,但你只提供了其中一个:

  function Ident(X: Real; Y: Real) return Real is
F(Result(N-1));
英文:

Your function takes two arguments, but you've only supplied one of them:

  function Ident(X: Real; Y: Real) return Real is
F(Result(N-1));

huangapple
  • 本文由 发表于 2023年3月12日 13:31:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/75711227.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定