对象需要数组 (A, b),而客户端需要包含元素 (A, b) 的类数组

Object requires array of (A, b) while client has array of class with elements (A, b)

本文关键字:数组 元素 对象 客户端 包含      更新时间:2023-10-16

>我正在尝试构建一个求解器对象。 它打算执行的算法大约是:

  • 接受描述系统 Ax = b 的输入。
  • 使用最小二乘法求解 x(系统对于所考虑的情况过度确定(
  • 计算 b' = Ax,给定最小二乘 x 的预期 b
  • 返回 b'

其他一些限制

  • 客户端以压缩形式存储 A 的元素(由 2 个元素ayaz 描述(,但它们需要扩展到完整的 50 个元素以进行矩阵计算。因此,求解器对象具有内部 A 数组(保存扩展形式(不会浪费内存
  • 客户端代码将ayazb存储为对象foo的元素,因此有一个foo数组,而不是几个包含ayazb的数组。此体系结构是不可协商的,这意味着:
    • 我无法使一个简单的函数doEverything(double *ay, double *az, double *b)
    • 求解器对象必须有一个内部 b 数组(用于馈送到矩阵数学函数 - 不同的foo::b元素是不可接受的(

我目前拥有的类需要正确使用以下公共函数:

  • void prepForInputWith(int nElements) – 调整内部数组的大小以允许 nElements 的空间(调用一次(
      如果不调用此
    • 函数,该类足够智能,可以重新调整自身大小,但是调用此函数可以节省每次添加新元素时重新分配的麻烦
  • void setAandB(double ay, double az, double b) – 在 A 和 b 中设置下一行数据(每个数据点调用一次(
  • void calculateXBestFit() – 反转 x 的系统(调用一次(
  • double returnBPrime() – 返回下一个单元格的答案(每个数据点调用一次,并且必须按照与 setNextResult 相同的顺序调用(

请注意,客户端必须按照调用setAandB()的顺序调用returnBPrime(),因为在returnBPrime()中计算 b'=Ax 时会重复使用 A 的条目(在 setAandB() 中计算并在 calculateXBestFit() 中使用(。删除此优化将使returnBPrime()可以按任何顺序调用,但会带来运行时损失。

我对此不满意,因为:

  • 客户端代码似乎比需要的更复杂
  • 这种方法中,一些在doEverything()方法中可能被视为理所当然的事情在这种方法中是不能的:

    • 在计算任何答案之前可以调用returnBPrime()
    • returnBPrime()可以调用与setAandB()不同的次数

    这意味着

    • 该类需要检查它是否被正确使用,使目标代码复杂化
    • 所有检查都必须在运行时执行,而似乎应该有足够的信息来确定该类在编译时是否正确使用

有没有更优雅的方法呢?

似乎此类的接口规范对类的客户端调用其函数的顺序施加了一些限制(如果它们希望获得有效结果(。我想不出任何方法可以在编译时强制执行该序列。

您可以做的是不要访问越界的数据。 你显然需要某种内部计数器来说明每个数组的哪个元素被修改或返回setAandB()returnBPrime().事实上,我会让这些函数中的每一个使用不同的计数器,我会calculateXBestFit()这两个计数器都设置为零。然后接下来对 returnBPrime()nElements调用将按顺序返回 b' 的元素,你可以调用另一个setAandB() nElements来准备下一次调用到calculateXBestFit().

有一些有用的运行时检查,但我认为它们的成本相当低。主要的一个是范围检查returnBPrime()使用的计数器。 一旦达到存储在 b' 中的数据的长度,后续调用将不会尝试读取 b'(但如果您可以达成一致,则可能会生成异常或错误消息(,直到下一次调用 calculateXBestFit() 之后。 只要此类的客户端持有合约,此运行时检查的成本只是表单if (counter < limit)条件下分支的成本。

setAandB()也有一个运行时检查,但我认为你已经考虑过一个(因为你说类会在需要时重新调整数组本身的大小(。

您需要就在每个数组的所有元素都由 setAandB() 设置之前调用 nElements calculateXBestFit() 会发生什么达成一致。 在我看来,最好的行为是对setAandB()的调用次数视为所需的数组大小,而不管为nElements提供了什么值。 这也意味着记住calculateXBestFit()使用的数组的大小,以便returnBPrime()使用该数字,而不是nElements,作为它实际允许从 b' 读取的值的数量。

顺便说一下,我还calculateXBestFit()计算 b' 的内容并将其存储在该对象的另一个数组中。 这意味着在此调用之后对象发生的任何情况(除了对calculateXBestFit()的另一个调用(不会影响对returnBPrime()的调用的结果。

让我们看看:这包括呼叫setAandB()太多次,呼叫setAandB()太少,呼叫returnBPrime()太多次,甚至将呼叫returnBPrime()与呼叫交错setAandB()以解决下一个问题。我能想到的唯一剩下的明显错误是调用returnBPrime()的次数太少,其结果只是客户端获得的数据将比应有的数据少。 而且我只看到一个您尚未承诺的运行时检查。