Общая функция усреднения Ады

У меня есть функция, которая усредняет определенное числовое значение из массива записей. Это значение представляет собой дельту либо натурального, либо перечисляемого типа. Я правильно суммирую значения, но мой вопрос заключается в следующем: как мне получить длину массива в общий тип, чтобы он мог делить как целые числа, так и числа дельта-типа?


ada
person n0dnarb    schedule 06.03.2011    source источник


Ответы (3)


В вашем массиве записей используйте атрибут «Длина»; это имеет то преимущество, что всегда работает, даже если ваши границы несколько странные, например -18..3, или перечисление, например сыры..фрукты.

Что-то типа:

Function Average( Input : In Array_of_Records ) Return float is
  -- You say you already have a summation function, so...
  Sum : Natural:= Summation( Input );
Begin
  Return Sum / Input'Length;
End Average;

Возможно, вам потребуется преобразовать числовые типы, сказав Float(Sum) или что-то подобное, поскольку Ада не выполняет автоматических «продвижений» типов.

person Shark8    schedule 06.03.2011
comment
это возвращает только число с плавающей запятой, я думал, что постер просил функцию, которая возвращала бы число с плавающей запятой или дискретный тип? - person NWS; 07.03.2011
comment
Истинный; возвращается часть с плавающей запятой "или" обрабатывается. - person Shark8; 08.03.2011
comment
Я интерпретировал это или как «он вернет то или иное в соответствии с созданием универсального», поскольку постер запросил универсальный :) - person NWS; 09.03.2011
comment
Лучшая интерпретация; печально, что, хотя целые числа и числа с плавающей запятой [и с фиксированной точкой] являются числовыми типами, общий числовой тип недоступен с индикаторами типов, используемыми в дженериках [то есть (‹›) или цифры ‹› и т. д.] ... но, вероятно, для этого есть веская причина (сложность компилятора, и может возникнуть соблазн использовать generic_number_1 и generic_number_2 с универсальной функцией, которая пыталась сложить их вместе). - person Shark8; 12.03.2011
comment
Если вы посмотрите на фактическую иерархию типов, «реальные» типы и «целочисленные» типы на самом деле представляют собой два отдельных поддерева, объединенных вместе как «числовые». я подозреваю, что именно поэтому дженерики не справляются с этим слишком хорошо. см. en.wikibooks.org/wiki/Ada_Programming/Types#The_Type_Hierarchy - person NWS; 14.03.2011

У этого есть некоторые недостатки, но ближе ли это к тому, что вы хотели?

NWS.

with Ada.Text_Io;

procedure Main is

   generic
      type Element_T is private;
      Zero : Element_T;
      One : Element_T;
      type Vec_T is array (Integer range <>) of Element_T;
      with function "+"(Left, Right : in Element_T) return Element_T is <>;
      with function "/"(Left, Right : in Element_T) return Element_T is <>;

   package Arrayops is
      function Sum (Vec : in Vec_T) return Element_T;
      function Count (Vec : in Vec_T) return Element_T;
      function Average (Vec : in Vec_T) return Element_T;
   end Arrayops;

   package body Arrayops is
      function Sum (Vec : in Vec_T) return Element_T is
         S : Element_T := Zero;
      begin
         for I in Vec'First .. Vec'Last loop
            S := S + Vec(I);
         end loop;
         return S;
      end Sum;

      function Count (Vec : in Vec_T) return Element_T is
         C : Element_T := Zero;
      begin
         for I in Vec'First .. Vec'Last loop
            C := C + One;
         end loop;
         return C;
      end Count;

      function Average (Vec : in Vec_T) return Element_T is
         S : constant Element_T := Sum (Vec);
         Len : constant Element_T := Count (Vec);
      begin
         return S / Len;
      end Average;
   end Arrayops;

   type Fl_Arr_T is array (Integer range <>) of Float;
   package Fl_Arr is new Arrayops (Element_T => Float,
                                   Zero => 0.0,
                                   One => 1.0,
                                   Vec_T => Fl_Arr_T);

   type Int_Arr_T is array (Integer range <>) of Integer;
   package Int_Arr is new Arrayops (Element_T => Integer,
                                    Zero => 0,
                                    One => 1,
                                    Vec_T => Int_Arr_T);


   My_Ints   : constant Int_Arr_T (1 .. 5) := (6,7,5,1,2);
   My_Floats : constant Fl_Arr_T (1 .. 7) := (6.1,7.2,5.3,1.4,2.5,8.7,9.7);

   Int_Sum   : constant Integer := Int_Arr.Sum (My_Ints);
   Int_Count : constant Integer := Int_Arr.Count (My_Ints);
   Int_Avg   : constant Integer := Int_Arr.Average (My_Ints);

   Float_Sum   : constant Float := Fl_Arr.Sum (My_Floats);
   Float_Count : constant Float := Fl_Arr.Count (My_Floats);
   Float_Avg   : constant Float := Fl_Arr.Average (My_Floats);

begin

   Ada.Text_Io.Put_Line ("Integers => Sum: " & Integer'Image (Int_Sum) & ", Count: " & Integer'Image (Int_Count) & ", Avg: " & Integer'Image (Int_Avg));
   Ada.Text_Io.Put_Line ("Floats   => Sum: " & Float'Image (Float_Sum) & ", Count: " & Float'Image (Float_Count) & ", Avg: " & Float'Image (Float_Avg));

end Main;

Результат :

Целые числа => Сумма: 21, Количество: 5, Среднее: 4

Плавающие => Сумма: 4.09000E+01, Счет: 7.00000E+00, Среднее: 5.84286E+00

person NWS    schedule 07.03.2011

Немного расширяем возможности Shark8 здесь...

Ада позволяет вам объявлять типы массивов как неограниченные. Что-то типа

type Array_of_Records is array (Natural range <>) of My_Record;

Дает вам тип, который можно использовать для массивов записей с начальным и конечным индексами массива, которые могут находиться где угодно в диапазоне Natural.

Одна из отличных вещей, которые я могу сделать с таким типом, — это использовать его в качестве параметра подпрограммы, например:

function Sum (Vector : in Array_of_Records) return Natural;

Итак, внутри этой подпрограммы, как мне узнать, где находятся границы массива? Используя атрибуты, например:

for index in Vector'first..Vector'last loop

or

for index in Vector'range loop

Конечно, чтобы это сработало, вы должны передать массив идеального размера вашей процедуре Sum. Предположим, что это не то, что у вас есть. Предположим, вместо этого у вас есть огромный массив (своего рода буфер), и не все значения действительны? Итак, вы отслеживаете допустимые значения и передаете только их с помощью среза.

Rec_Buffer : Array_of_Records (1..10_000);
Last_Valid_Rec : Natural := 0;
....
--// Rec_Buffer gets loaded with 2,128 values or something. We pass it into Sum
--// like so:
Ada.Text_IO ("Sum of vector is " & 
             natural'image(Sum (Rec_Buffer (1..Last_Valid_Rec));

(предупреждение - нескомпилированный код)

person T.E.D.    schedule 07.03.2011