我可以将值限制在Ada的范围内吗?

时间:2014-10-15 19:04:00

标签: ada

是否有一种很好的方法可以将一个值钳位(剪辑?,强制?)到Ada中的范围? 我现在已经这样做了:

timer := Integer'Max(timer, Integer(Half_Word'First));
timer := Integer'Min(timer, Integer(Half_Word'Last));
TIM8.TIM.ARR := Half_Word(timer);

但这有点笨重,我想把变量计时器钳在Half_Word的范围内。

2 个答案:

答案 0 :(得分:5)

Ada没有内置的方法来做到这一点。如果这是你将反复做的事情,并且在不同的类型上,这样的通用可能会有所帮助:

generic
     type Source_Type is range <>;
     type Destination_Type is range <>;
function Saturate (X : Source_Type) return Destination_Type;

function Saturate (X : Source_Type) return Destination_Type is
    Result : Source_Type;
begin
    Result := Source_Type'Max (X, Source_Type (Destination_Type'First));
    Result := Source_Type'Min (Result, Source_Type (Destination_Type'Last));
    return Destination_Type (Result);
end Saturate; 

...

function Saturate_To_Half_Word is new Saturate (Integer, Half_Word); 

... 

TIM8.TIM.ARR := Saturate_To_Half_Word(timer);

编辑:以上假设Destination_Type的范围将始终包含在Source_Type中。如果不是这样,代码将引发Constraint_Error。即使Destination_Type可能大于Source_Type

也可以使用的替代方法
function Saturate (X : Source_Type) return Destination_Type is
    type Largest_Int is range System.Min_Int .. System.Max_Int;
    Result : Source_Type;
begin
    Result := X;
    if Largest_Int (Destination_Type'First) in
         Largest_Int (Source_Type'First) .. Largest_Int (Source_Type'Last) then
        Result := Source_Type'Max (Result, Source_Type (Destination_Type'First));
    end if;
    if Largest_Int (Destination_Type'Last) in
         Largest_Int (Source_Type'First) .. Largest_Int (Source_Type'Last) then
        Result := Source_Type'Min (Result, Source_Type (Destination_Type'Last));
    end if;
    return Destination_Type (Result);
end Saturate; 

您必须仔细编码以避免类型冲突,同时避免提升Constraint_Error

编辑2:我向后FirstLast。固定的。

编辑3:按照Simon的建议,这也有效:

function Saturate (X : Source_Type) return Destination_Type is
    type Largest_Int is range System.Min_Int .. System.Max_Int;
    Result : Largest_Int;
begin
    Result := Largest_Int (X);
    Result := Largest_Int'Max (Result, Largest_Int (Destination_Type'First));
    Result := Largest_Int'Min (Result, Largest_Int (Destination_Type'Last));
    return Destination_Type (Result);
end Saturate; 

这看起来更简单,但效率可能略低,因为它在运行时涉及更多类型转换。 (请注意,前一个示例中复杂的条件是可以在编译时评估的所有条件,因此不应生成任何代码 - 加上它可能导致'Max和/或'Min操作这是假设编译器使用“宏扩展​​”模型进行泛型实例化,就像GNAT一样。一个非常好的编译器也可以在后一个代码中找出相同类型的优化,但它更难。)

答案 1 :(得分:1)

你可以使用默认设置使这更容易使用 - 最大的问题[维护明智]然后就是看起来比实际情况还要多,这是最大的缺点是编译器在编译时没有检查/强制DESTINATION_TYPE作为SOURCE_TYPE子集的约束。

generic
  type Source_Type is range <>;
  type Destination_Type is range <>;

  S_First : Long_Long_Integer:= Long_Long_Integer(Source_Type'First);     --' FIX FOR
  S_Last  : Long_Long_Integer:= Long_Long_Integer(Source_Type'Last);      --' BUGGY 
  D_First : Long_Long_Integer:= Long_Long_Integer(Destination_Type'First);--' SYNTAX
  D_Last  : Long_Long_Integer:= Long_Long_Integer(Destination_Type'Last); --' HIGHLIGHT.
function Saturate (X : Source_Type) return Destination_Type
 with Pre => 
          D_First >= S_First
      and D_Last  <= S_Last;

function Saturate (X : Source_Type) return Destination_Type is
  X_Pos : constant Long_Long_Integer:= Long_Long_Integer(X);
begin      
  if X_Pos in D_First..D_Last then
     return Destination_Type(X);
  elsif X_Pos < D_First then
     return Destination_Type'First; --'
  else
     return Destination_Type'Last;  --'
  end if;
end Saturate;

使用示例:

subtype K is Integer range 2..24;
subtype J is Integer range 3..10;

Function P is new Saturate(Source_Type      => K,
                           Destination_Type => J
                          );