2

让我首先提供一些上下文,希望它能让问题更清楚:我正在从我希望操作的硬件接收字节向量数据。由于大小和时间限制,我不希望将日期转换为更大的大小。我想允许计算的中间值超出字节范围。这不是标量的问题(中间值保存在寄存器中,编译器不会为中间值发出约束错误)。

但是,在使用用户定义的运算符时,它更加棘手。我们可以将结果提升为更大的大小,但随后分配回原始类型将需要显式转换(子类型不能具有混合大小)。例如,在第 24 行下面的代码中将变为Z := To_Point((X + Y) / 2);It is a solution,但我希望找到一个不需要添加“To_Point”功能的解决方案。

我在 Ada.Numerics 中查看了向量的实现,它使用的是实数值,并且不提升中间值,例如:

function "+" (Left, Right : Real_Vector) return Real_Vector;

这可能会导致约束错误,但与标量计算(取决于机器)相比,它更有可能导致一些准确性损失(因为实数的表示方式)。

     1. pragma Ada_2012;
     2. with Ada.Text_IO; use Ada.Text_IO;
     3.
     4. procedure Inter_Value is
     5.     type Byte is new Integer Range 0..255 with Size => 8;
     6.     A, B, C : Byte;
     7.
     8.     type Point is array(1..2) of Byte with Convention => C, Size => 2*8;
     9.     X, Y, Z : Point;
    10.
    11.     function "+" (Left, Right : Point) return Point is (Left (1) + Right (1), Left (2) + Right(2));
    12.     function "/" (Left : Point; Right : Byte) return Point is (Left (1) / Right, Left (2) / Right);
    13.
    14. begin
    15.     Put_Line(C'Size'Image);
    16.     A := 100;
    17.     B := 200;
    18.     C := (A + B) / 2;           -- Ok, intermediate value in register
    19.     Put_Line("C = " & C'Image);
    20.
    21.     Put_Line(X'Size'Image);
    22.     X := (100, 100);
    23.     Y := (200, 200);
    24.     Z := (X + Y) / 2;           -- CONSTRAINT_ERROR, intermediate value in Point
    25.     Put_Line("Z = " & Z(1)'Image & Z(2)'Image);
    26. end;
4

2 回答 2

4

从评论中回顾一下:声明Byte等同于

type Byte'Base is new Integer;
subtype Byte is Byte'Base range 0 .. 255 with Size => 8;

重要的是,预定义的运算符是为Byte'Base. 要获得类似的行为,Point您必须明确模仿:

type Point_Base is array (1..2) of Byte'Base;

function "+" (Left : in Point_Base; Right : in Point_Base) return Point_Base is
   (Left (1) + Right (1), Left (2) + Right(2) );
function "/" (Left : in Point_Base; Right : in Byte'Base) return Point_Base is
   (Left (1) / Right, Left (2) / Right);

subtype Point is Point_Base with
   Dynamic_Predicate => (for all P of Point => P in Byte);

现在(X + Y)给出Point_Base传递给的 a "/",它也给出了 a Point_Base。然后检查结果是否满足Z赋值前的子类型的约束。

于 2021-05-24T09:47:30.140 回答
1

X+Y应该是一个点,因此每个组件都应该保持在字节范围内,但事实并非如此。

你为什么不像这样重写第 24 行?:

    Z := (X/2 + Y/2);

由于每个 X 和 Y 分量不能超过 255,因此添加其中的一半始终保持在该范围内。

于 2021-05-23T08:44:05.820 回答