Ada:提升向量上用户定义运算符中间值的最佳方法是什么?

Ada:提升向量上用户定义运算符中间值的最佳方法是什么?,ada,ada2012,Ada,Ada2012,首先让我提供一些背景,希望它能让问题变得更清楚: 我正在从我希望操作的硬件接收字节向量数据。 由于尺寸和时间限制,我不希望将日期转换为更大的尺寸。 我希望允许计算的中间值超过字节范围。 这不是标量的问题(中间值保存在寄存器中,编译器不会对中间值发出约束错误) 但是,在处理用户定义的运算符时,它更为棘手。我们可以将结果提升到更大的大小,但随后将赋值返回到原始类型将需要显式转换(子类型不能有混合大小)。例如,在第24行下面的代码中,将变成Z:=To_点((X+Y)/2)这是一个解决方案,但我希望找到

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

但是,在处理用户定义的运算符时,它更为棘手。我们可以将结果提升到更大的大小,但随后将赋值返回到原始类型将需要显式转换(子类型不能有混合大小)。例如,在第24行下面的代码中,将变成
Z:=To_点((X+Y)/2)这是一个解决方案,但我希望找到一个不需要添加“to_Point”函数的解决方案

我研究了Ada中向量的实现。Numerics它使用实值,不提升中间值,例如:

函数“+”(左、右:实_向量)返回实_向量

这可能会导致约束错误,但与标量计算(依赖于机器)相比,更可能导致精度损失(因为实数的表示方式)

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

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

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

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

从注释中重述:
字节的声明相当于

type Byte'Base is new Integer;
subtype Byte is Byte'Base range 0 .. 255 with Size => 8;
重要的是,预定义的运算符是为
Byte'Base
定义的。要获得
的类似行为,您必须显式模拟:

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)
给出了一个
点基数
,它被传递到
“/”
,这也给出了一个
点基数
。然后在赋值之前检查结果是否满足子类型
Z
的约束。

原因
(a+B)/2
与寄存器无关。它之所以有效,是因为调用的
“+”
被定义为
函数“+”(左:整数;右:整数)返回整数
对不起,实际上
Byte
“+”
定义中的类型被定义为操作并返回
Byte'Base
,并且
Byte'Base
被声明为与
Integer
@JeffreyR.Carter具有相同的表示形式,谢谢-这很有意义(整数和字节不兼容,但显然字节的基和字节是兼容的)。如果我只能将其扩展到向量……谢谢Frédéric。为了回答您的问题:(I)第24行是一个示例,它可以是任何表达式。和(ii)它总比没有好,但对于奇数仍然不准确。你说奇数不准确是什么意思?我的意思是,这是标准的整数除法截断数frédéric,例如:(7/2+5/2)=(3+2)=5,(7+5)/2=12/2=6。好吧,我不明白你的意思:)应该是
Z:=(X/2)+(Y/2)+(X mod 2+Y mod 2)/2)
。另请参见。ADA2012谓词的一个很好的答案和一个很好的(对我来说很有用!)说明。中间值(X+Y)则是点_基,如果没有(动态地,如果发生溢出)引发Constant错误,则不能存储在点中。动态谓词检查值是否不超过字节范围,但是,“点”的大小仍然与“点_基”的大小相同,因此仍然需要对输入进行转换(它不是二进制兼容的,不能直接应用于硬件发送的缓冲区)--也就是说,将输入单次转换为更大的尺寸可能仍然是正确的方法-它更简单,并且避免了以后的许多中间转换。我忽略了尺寸复杂性,只关注功能性。处理这类事情的基本规则是使用与H/W布局和另一种类型,其范围与处理所需的范围和编译器确定的布局相对应。输入立即转换为内部类型,而内部类型在输出之前转换为外部类型。因此,您的内部类型可能是如上所述的
(因此,它检查所有最终值是否在
字节中,并且您需要为输入和输出添加一个类型
HW_点
)。
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);