Float to String: проблема с длиной строки - PullRequest
2 голосов
/ 16 апреля 2019

Я хотел бы преобразовать значение с плавающей точкой в ​​строку и создал следующий короткий пример:

with Ada.Text_IO;

procedure Example is
   A : constant Float := -1.234;
   B : constant Float := 123_456.789;
   C : constant Float := 987.654_321;

   package Float_IO is new Ada.Text_IO.Float_IO (Num => Float);

   String_Float_A : String := "     ";
   String_Float_B : String := "          ";
   String_Float_C : String := "       ";
begin
   Ada.Text_IO.Put_Line (Float'Image (A));
   Ada.Text_IO.Put_Line (Float'Image (B));
   Ada.Text_IO.Put_Line (Float'Image (C));

   Float_IO.Put
     (To   => String_Float_A,
      Item => A,
      Aft  => 2,
      Exp  => 0);

   Float_IO.Put
     (To   => String_Float_B,
      Item => B,
      Aft  => 2,
      Exp  => 0);

   Float_IO.Put
     (To   => String_Float_C,
      Item => C,
      Aft  => 2,
      Exp  => 0);

   Ada.Text_IO.Put_Line (String_Float_A);
   Ada.Text_IO.Put_Line (String_Float_B);
   Ada.Text_IO.Put_Line (String_Float_C);
end Example;

Моя проблема: мне нужно создать строковые переменные перед вызовом процедуры Put достаточной длины. Как это можно сделать динамически во время выполнения? В основном мне нужно выяснить количество цифр перед точкой. Тогда достаточная длина строки будет: 1 (sign) + Number_Of_Dots + 1 (decimal separator) + Aft.

Ответы [ 3 ]

3 голосов
/ 17 апреля 2019

Количество цифр перед точкой десятичного числа можно вычислить, вычислив 1 плюс целую часть общего логарифма (основание 10) целой части числа.

В Ada:

    N := Integer (Float'Floor (Log (Float'Floor (abs X), 10.0))) + 1;

Ваша программа должна быть снабжена Ada.Numerics.Elementary_Functions.Вы должны добавить пробел для знака минус, если число отрицательное.

Эта формула не работает, если целая часть равна 0, но тогда N, очевидно, равно 1.

3 голосов
/ 19 апреля 2019

В вашем примере используется Float, возможно, в качестве прокси для более конкретного реального типа .Если ваши фактические данные лучше смоделировать как десятичный тип с фиксированной запятой , обсуждается здесь , не забывайте об удобстве отредактированный выводдля десятичных типов , обсуждается здесь .В приведенном ниже примере используется строка "+Z_ZZZ_ZZ9.99" для построения картинки желаемого выхода Image.

Консоль:

-        1.23
+  123,456.79
+      987.65
+1,000,000.00

Код:

with Ada.Text_IO;         use Ada.Text_IO;
with Ada.Text_IO.Editing; use Ada.Text_IO.Editing;

procedure Editing is

   type Number is delta 0.000_001 digits 12;
   type Numbers is array (Positive range <>) of Number;
   package Number_Output is new Decimal_Output (Number);
   Format_String : constant String  := "+Z_ZZZ_ZZ9.99";
   Format        : constant Picture := To_Picture (Format_String);
   Values        : constant Numbers :=
     (-1.234, 123_456.789, 987.654_321, Number'Last);

begin
   for Value of Values loop
      Put_Line (Number_Output.Image (Value, Format));
   end loop;

конец редактирования;

2 голосов
/ 17 апреля 2019

Вы можете сделать функцию для выполнения работы, что-то вроде этого:

with Ada.Text_IO;
with Ada.Strings.Fixed;
procedure Marcello_Float is

   function Image (Item : Float;
                   Aft : Ada.Text_IO.Field := Float'Digits - 1;
                   Exp : Ada.Text_IO.Field := 3) return String
   is
      package Float_IO is new Ada.Text_IO.Float_IO (Float);
      Result : String (1 .. 128);
   begin
      Float_IO.Put (To   => Result,
                    Item => Item,
                    Aft  => Aft,
                    Exp  => Exp);
      return Ada.Strings.Fixed.Trim (Result,
                                     Side => Ada.Strings.Both);
   end Image;

   A : constant Float := -1.234;
   B : constant Float := 123_456.789;
   C : constant Float := 987.654_321;

   A_Image : constant String := Image (A, Aft => 2, Exp => 0);
   B_Image : constant String := Image (B, Aft => 2, Exp => 0);
   C_Image : constant String := Image (C, Aft => 2, Exp => 0);

   use Ada.Text_IO;
begin
   Put_Line (A'Image & " => " & A_Image);
   Put_Line (B'Image & " => " & B_Image);
   Put_Line (C'Image & " => " & C_Image);
end Marcello_Float;

Я сделал Result смехотворно долго. Я понимаю, что для точного расчета размера на самом деле нужно ответить на ваш первоначальный вопрос; просто ленивый.

...