在 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 回答来说太长了......