在 Ada 的 while 循环中打印最后一个弧度
Print the last rad in while loop in Ada
我在 Ada 中写了一个程序,要求用户输入 startprise、stopppris、step 和 procent,程序将计算并打印结果。
我的代码很好,我没有问题,我可以打印除最后一行以外的所有值。
用户会告诉以下值:
起步价:10.0
停止价格:11.0
步长:0.1
百分比:10.0
结果应该是这样的:
10.00 1.00 11.00
10.10 1.01 11.11
----等等
10.90 1.09 11.99
11.00 1.10 12.10
我的代码无法打印最后一行,而循环停止在 10.90 1.09 11.99,我该如何修复它并打印最后一行:
enter code here
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Float_Text_IO; use Ada.Float_Text_IO;
procedure Main is
startpris, stoppris,step:Float := 0.0 ;
procent: Float := -0.1;
priseftermoms, moms: Float;
p : Float := 100.0;
I : Integer:= 1;
J : Float := 0.0;
x : Float := -0.1;
index: Float := 0.0;
begin
while startpris <= J loop
Put("Första Pris: ");
Get(startpris);
if startpris < J then
Put_Line (" Felaktigt värde!");
end if;
end loop;
while stoppris <= J or stoppris <= startpris loop
Put("Sista Pris: ");
Get(stoppris);
--stoppris := Float'Value(Get_Line);
if startpris > stoppris then
Put_Line ("Felaktigt värde!");
end if;
end loop;
while step <= J loop
Put("Steg: ");
Get(step);
--step := Float'Value (Get_Line);
if step < J then
Put_Line (" Felaktigt värde!");
end if;
end loop;
while procent < J or procent > p loop
Put("Momsprocent: ");
Get(procent);
if procent <= x then
Put_Line (" Felaktigt värde!");
end if;
if procent > P then
Put_Line (" Felaktigt värde!");
end if;
end loop;
Put_Line("");
Put_Line("=================== Momstabell =====================");
Put_Line("Pris utan moms Moms Pris med moms");
while stoppris >= startpris loop
moms := (startpris * procent)/ p;
priseftermoms := moms + startpris;
put(startpris,fore=>1, aft => 2, exp=> 0);
put(" ");
put(moms,fore=>1, aft => 2, exp=> 0);
put(" ");
put(priseftermoms,fore=>1, aft => 2,exp=> 0);
Put_Line("");
startpris := startpris + step;
end loop;
end Main;
您的错误在于认为使用 floating-point 数字(浮点型)的计算与使用带小数部分的 10 进制数字的计算完全相同。在二进制计算机中,floating-point 数字以二进制表示,基数为 2,这意味着像 1/10 这样的分数,虽然在源代码和输入文本中写为 0.1,但并不完全表示,而是用一个小的取决于尾数中位数的错误。因此,该程序实际计算的值要么是 0.099...9x...,其中数字 x 不是 9,要么是 0.100...0x...,其中数字 x 不为零。也就是说,计算中的值要么略小于 0.1,要么略大于 0.1。
这意味着在你的程序中,由于最后的while-loop将“step”添加到“startpris”,因此存在初始错误(从输入的10进制数到二进制数的转换)和一个累积误差(来自重复添加“步骤”及其初始误差)。结果是,经过 N 次迭代后,“startpris”的值并不完全是 10.0 + N*0.1,而是略有不同。因此,在 10 次迭代之后,当您希望循环打印出“startpris”= 110.0 的值时,“startpris”的实际值可能会(并且似乎会发生)略大于 110.0。然后 while-loop 条件为 False,并且不会针对“startpris”的值执行循环。
要更正程序,您可以使 while-loop 条件容忍这个小错误,例如
while stoppris >= startpris - step/2.0 loop
或者您可以计算所需的整数步数,然后循环计算该步数,例如
steps : constant Natural := Natural ((stoppris - startpris) / step);
pris : Float;
...
for num_step in 0 .. steps loop
pris := startpris + Float(num_step) * step;
moms := (pris * procent) / p;
... and so on, using "pris" instead of "startpris".
请注意,在“steps”声明中转换为 Natural 会将 floating-point 数字四舍五入为最接近的整数。这使得它可以容忍二进制 floating-point 表示中的小错误。
我推荐第二种方法,计算步数然后使用 for-loop。
还有第三种解决方案,适用于处理小数位数固定的金额,例如欧元和美分写成 xxx.yy,其中 yy 是美分的数量。然后你可以使用 Ada 的“十进制 fixed-point 类型”来获得以 10 为基数的两位小数的精确计算。但这对于 SO 回答来说太长了......
我在 Ada 中写了一个程序,要求用户输入 startprise、stopppris、step 和 procent,程序将计算并打印结果。
我的代码很好,我没有问题,我可以打印除最后一行以外的所有值。
用户会告诉以下值:
起步价:10.0
停止价格:11.0
步长:0.1
百分比:10.0
结果应该是这样的:
10.00 1.00 11.00
10.10 1.01 11.11
----等等
10.90 1.09 11.99
11.00 1.10 12.10
我的代码无法打印最后一行,而循环停止在 10.90 1.09 11.99,我该如何修复它并打印最后一行:
enter code here
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Float_Text_IO; use Ada.Float_Text_IO;
procedure Main is
startpris, stoppris,step:Float := 0.0 ;
procent: Float := -0.1;
priseftermoms, moms: Float;
p : Float := 100.0;
I : Integer:= 1;
J : Float := 0.0;
x : Float := -0.1;
index: Float := 0.0;
begin
while startpris <= J loop
Put("Första Pris: ");
Get(startpris);
if startpris < J then
Put_Line (" Felaktigt värde!");
end if;
end loop;
while stoppris <= J or stoppris <= startpris loop
Put("Sista Pris: ");
Get(stoppris);
--stoppris := Float'Value(Get_Line);
if startpris > stoppris then
Put_Line ("Felaktigt värde!");
end if;
end loop;
while step <= J loop
Put("Steg: ");
Get(step);
--step := Float'Value (Get_Line);
if step < J then
Put_Line (" Felaktigt värde!");
end if;
end loop;
while procent < J or procent > p loop
Put("Momsprocent: ");
Get(procent);
if procent <= x then
Put_Line (" Felaktigt värde!");
end if;
if procent > P then
Put_Line (" Felaktigt värde!");
end if;
end loop;
Put_Line("");
Put_Line("=================== Momstabell =====================");
Put_Line("Pris utan moms Moms Pris med moms");
while stoppris >= startpris loop
moms := (startpris * procent)/ p;
priseftermoms := moms + startpris;
put(startpris,fore=>1, aft => 2, exp=> 0);
put(" ");
put(moms,fore=>1, aft => 2, exp=> 0);
put(" ");
put(priseftermoms,fore=>1, aft => 2,exp=> 0);
Put_Line("");
startpris := startpris + step;
end loop;
end Main;
您的错误在于认为使用 floating-point 数字(浮点型)的计算与使用带小数部分的 10 进制数字的计算完全相同。在二进制计算机中,floating-point 数字以二进制表示,基数为 2,这意味着像 1/10 这样的分数,虽然在源代码和输入文本中写为 0.1,但并不完全表示,而是用一个小的取决于尾数中位数的错误。因此,该程序实际计算的值要么是 0.099...9x...,其中数字 x 不是 9,要么是 0.100...0x...,其中数字 x 不为零。也就是说,计算中的值要么略小于 0.1,要么略大于 0.1。
这意味着在你的程序中,由于最后的while-loop将“step”添加到“startpris”,因此存在初始错误(从输入的10进制数到二进制数的转换)和一个累积误差(来自重复添加“步骤”及其初始误差)。结果是,经过 N 次迭代后,“startpris”的值并不完全是 10.0 + N*0.1,而是略有不同。因此,在 10 次迭代之后,当您希望循环打印出“startpris”= 110.0 的值时,“startpris”的实际值可能会(并且似乎会发生)略大于 110.0。然后 while-loop 条件为 False,并且不会针对“startpris”的值执行循环。
要更正程序,您可以使 while-loop 条件容忍这个小错误,例如
while stoppris >= startpris - step/2.0 loop
或者您可以计算所需的整数步数,然后循环计算该步数,例如
steps : constant Natural := Natural ((stoppris - startpris) / step);
pris : Float;
...
for num_step in 0 .. steps loop
pris := startpris + Float(num_step) * step;
moms := (pris * procent) / p;
... and so on, using "pris" instead of "startpris".
请注意,在“steps”声明中转换为 Natural 会将 floating-point 数字四舍五入为最接近的整数。这使得它可以容忍二进制 floating-point 表示中的小错误。
我推荐第二种方法,计算步数然后使用 for-loop。
还有第三种解决方案,适用于处理小数位数固定的金额,例如欧元和美分写成 xxx.yy,其中 yy 是美分的数量。然后你可以使用 Ada 的“十进制 fixed-point 类型”来获得以 10 为基数的两位小数的精确计算。但这对于 SO 回答来说太长了......