英文:
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 <>) 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;
The file euler.ads is
--
-- Solving a differential equation.
-- Demonstrates generic floating point type.
--
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);
And the file euler.adb is
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;
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'First) := Init;
for N in Result'First + 1 .. Result'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's the initial value of
-- X? guessing here ...
Current_X : Float_Type := 0.0;
begin
Result (Result'First) := Init;
for N in Result'First + 1 .. Result'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));
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论