是否有一种很好的方法可以将一个值钳位(剪辑?,强制?)到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的范围内。
答案 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:我向后First
和Last
。固定的。
编辑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
);