在我的案例中,我可以计算一个元素而不循环遍历所有前面的元素(请参阅问题正文)吗?

发布于 2024-09-30 09:39:40 字数 856 浏览 2 评论 0原文

我有 2 个相同长度的双精度数组。数组a填充了一些数据,数组b要进行计算。

数组 b 的每个元素等于数组 a 中的相应值加上数组 b 中所有先前元素的加权和。

加权和的计算方法是将所有这些元素相加,每个元素乘以一个系数,该系数等于其与我们计算的当前元素的距离除以前一个子集中的元素数量。

为了实现这一点,我循环遍历我计算的每个元素的整个前面的子集。

这个可以优化吗?我没有足够的数学技能,但我怀疑我只能使用第一个前面的元素来计算下一个元素,因为每个元素都已经从前面的集合中派生出来,并且包含它已经加权的所有信息。也许我可以调整权重公式并获得相同的结果,而无需第二级循环?

这似乎是 Scala 中的一个例子(我不确定它是否正确:-]​​)。由于实际项目使用负索引,因此根据上面所写的任务,将 a(1) 和 a(2) 视为 a(0) 之前。


import scala.Double.NaN
val a = Array[Double] (8.5, 3.4, 7.1, 5.12, 0.14, 5)
val b = Array[Double] (NaN, NaN, NaN, NaN, NaN, 5)
var i = b.length - 2
while (i >= 0) {
  b(i) = a(i) + {
    var succession = 0.0
    var j = 1
    while (i + j < b.length) {
      succession += b (i+j) * (1.0-j.toDouble/(b.length - i))
      j += 1
    }
    succession
  }
  i -= 1
}
b.foreach((n : Double) => println(n))

I have 2 arrays of Doubles of the same length. Array a is filled with some data, array b is to be calculated.

Each element of the array b equals a corresponding value from array a plus a weighted sum of all preceding elements in the array b.

A weighted sum is calculated by adding all those elements each multiplied by a coefficient which equals its distance from the current element we calculate divided by number of elements in the preceding subset.

To implement this I loop through the whole preceding subset for each element I calculate.

Can this be optimized? I have not enough maths skills, but I suspect that I could only use the first preceding element to calculate every next as every element is already derived from the preceding set and contains all the information of it already weighted. Maybe I can just adjust the weight formula and get the same result without a second level looping?

This seems to be an example in Scala (I am not sure if it is correct :-]). As the real project uses negative indices, treat a(1) and a(2) as preceding a(0) in terms of the task written above.


import scala.Double.NaN
val a = Array[Double] (8.5, 3.4, 7.1, 5.12, 0.14, 5)
val b = Array[Double] (NaN, NaN, NaN, NaN, NaN, 5)
var i = b.length - 2
while (i >= 0) {
  b(i) = a(i) + {
    var succession = 0.0
    var j = 1
    while (i + j < b.length) {
      succession += b (i+j) * (1.0-j.toDouble/(b.length - i))
      j += 1
    }
    succession
  }
  i -= 1
}
b.foreach((n : Double) => println(n))

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

此刻的回忆 2024-10-07 09:39:40

我假设距离是两个元素的绝对差。

如果我理解正确的话,b 的每个元素都必须是:

b(i) = a(i) + sum(j = 1 to i-1) (a(j) * (abs(a(i) - a(j)) / i )

b(i) = a(i) + sum(j = 1 to i-1) ( abs(a(j)*a(j) - a(j)*a(i)) / i )

现在,如果我们可以用 b(i)< 来写 b(i+1) /code> 我们会做到的。

问题是每个权重都取决于 a(i)a(j)(更糟糕的是,这是绝对差异) )。

这就是为什么我们不能再简化上面的内容,也不能从每个总和中“提取”知识以在下一个总和中使用它。

I assume the distance is the absolute difference of two elements.

If I understood it correctly each element of b has to be:

b(i) = a(i) + sum(j = 1 to i-1) (a(j) * (abs(a(i) - a(j)) / i )

b(i) = a(i) + sum(j = 1 to i-1) ( abs(a(j)*a(j) - a(j)*a(i)) / i )

Now, if we could write b(i+1) in terms of b(i) we would have done it.

The problem is that each weight depends on both, a(i) and a(j) (and even worse, it is the absolute difference).

That's why we can't simplify the above anymore and can't "extract" knowledge from each sum to use it in the next one.

清音悠歌 2024-10-07 09:39:40

这就是你想做的事?

f(x_n) := g(x_0,..,x_(n-1)) + h(x_n)

只有找到一个等效函数来替换g,才能优化嵌套循环。实际上,我不知道加权和的确切含义。我想,它是

g(x_0,..,x_(n-1)) = (x_0 + ... + x_(n-1)) / (n-1)

(添加所有值并除以值的数量)

在这种情况下,您可以存储总和并重用它:

a := (x_0 + ... + x_(n-2))
g(x_0,..,x_(n-1)) = (a + x_(n-1)) / (n-1)

这将消除嵌套循环。

就 Java 而言(实现我的加权总和的想法):

double[] x = initX();
double[] y = new double[x.length];
double sum = 0;
y[0] = h(x[0]);
for (int i = 1; i < x.length; i++) {
  sum = sum + x[i-1];    
  y[i] = sum / (i-1) + h(x[i]);
}

That's what you're trying to do?

f(x_n) := g(x_0,..,x_(n-1)) + h(x_n)

The nested loop can only be optimized if we can find a equivalent function to replace g. Actually, I don't know the exact meaning of weighted sum. I guess, it's

g(x_0,..,x_(n-1)) = (x_0 + ... + x_(n-1)) / (n-1)

(adding all values and dividing by the number of values)

In that case, you could store the sum and reuse it:

a := (x_0 + ... + x_(n-2))
g(x_0,..,x_(n-1)) = (a + x_(n-1)) / (n-1)

This would eliminate the nested loop.

In terms of Java (implements my idea of a weighted sum):

double[] x = initX();
double[] y = new double[x.length];
double sum = 0;
y[0] = h(x[0]);
for (int i = 1; i < x.length; i++) {
  sum = sum + x[i-1];    
  y[i] = sum / (i-1) + h(x[i]);
}
痴梦一场 2024-10-07 09:39:40

这是 b 的方程吗?
(来自 http://texify.com/?$b[k]%20=%20a[k]% 20+%20\frac{\sum_{i%20=%200}^{k%20-%201}{a[i]%20/%20(ki)}}{k%20-%201}$ )

替代文字

Is this the equation for b?
(from http://texify.com/?$b[k]%20=%20a[k]%20+%20\frac{\sum_{i%20=%200}^{k%20-%201}{a[i]%20/%20(k-i)}}{k%20-%201}$)

alt text

梦太阳 2024-10-07 09:39:40

你说:

通过添加所有这些元素,每个元素乘以一个系数,该系数等于我们计算的与当前元素的距离

很可能您无法从先前的元素预测当前元素,因此您至少必须计算每个元素的这些距离:距离(i,j),其中i < n和j<我。这意味着循环两次。

我认为如果距离是线性函数,那么这可以优化,但通常距离是非线性的(因此它是正的)。所以我的猜测是你必须循环两次。

You said:

by adding all those elements each multiplied by a coefficient which equals its distance from the current element we calculate

Most likely you can't predict the current element from the previous elements so you will at least have to compute those distances for each element: distance(i,j) where i < n and j < i. This means looping twice.

I think this could be optimized if distance was a linear function but conventionally a distance is non linear (so that it is positive). So my guess is that you'll have to loop twice.

行至春深 2024-10-07 09:39:40

需要考虑三种不同的情况。

(1) 权重不变。

示例/解决方案:

val xs = List(1,2,3,4,5)
val ws = List(3,2,5,1,4)
// Desired:
  // 1
  // 1*3 + 2
  // 1*3 + 2*2 + 3
  // 1*3 + 2*2 + 3*5 + 4
  // 1*3 + 2*2 + 3*5 + 4*1 + 5
val mul = (xs,ws).zipped.map(_ * _)   // 1*3, 2*2, 3*5, etc.
val cuml = mul.scanLeft(0)(_ + _)     // Cumulative sums of the above
val ans = (xs,cuml).zipped.map(_ + _) // Put it all together

(2) 权重确实发生了变化,但变化是线性缩放因子,就好像它们表示沿直线的有符号距离一样。然后我们让 (d1-a)*x1 + (d2-a)*x2 + ... + (dn-a)*xn = y 成为我们之前的答案,假设我们在 <代码>a;那么如果我们移动到 b 我们可以将其修改为 (d1-b)*x1... = (d1-a+ab)*x1+.. . = (d1-a)*x1+(ab)*x1+... 这表明我们只需要 x 值和 <距离从旧答案中得到新答案。所以:

val xs = List(1,2,3,4,5)
val ds = List(3,2,5,1,4)              // Treat these as distances along a line
// Desired:
  // 1
  // (3-2)*1 + 2
  // (3-5)*1 + (2-5)*2 + 3
  // (3-1)*1 + (2-1)*2 + (5-1)*3 + 4
  // (3-4)*1 + (2-4)*2 + (5-4)*3 + (1-4)*4 + 5
val ws = ds.map(_ - ds.head)          // Distances from the first element
val mul = (xs,ws).zipped.map(_ * _)
val cuml = mul.scanLeft(0)(_ + _)
// If we used this alone we would get:
  // 1
  // (3-3)*1 + 2            <-- should be subtracting 2, not 3!
  // (3-3)*1 + (2-3)*2 + 3  <-- should be subtracting 5, not 3!
  // etc.
val cumlx = xs.scanLeft(0)(_ + _)             // Need this to fix up our sums
val fix = (cumlx,ws).zipped.map(-1 * _ * _)   // This will actually do it
val ans = (xs,cuml,fix).zipped.map(_ + _ + _)

理解它是如何工作的最好方法是逐个语句地拆开它并手工写出来,以验证它实际上正在计算我们想要它计算的内容。

(3) 随着您的前进,权重的变化并不一致。到平面上点的距离往往具有该属性,因为平方根的非线性基本上意味着您必须重新计算每个点。所以你每次只需要进行整个计算。

There are three separate cases to consider.

(1) The weights don't change.

Example/solution:

val xs = List(1,2,3,4,5)
val ws = List(3,2,5,1,4)
// Desired:
  // 1
  // 1*3 + 2
  // 1*3 + 2*2 + 3
  // 1*3 + 2*2 + 3*5 + 4
  // 1*3 + 2*2 + 3*5 + 4*1 + 5
val mul = (xs,ws).zipped.map(_ * _)   // 1*3, 2*2, 3*5, etc.
val cuml = mul.scanLeft(0)(_ + _)     // Cumulative sums of the above
val ans = (xs,cuml).zipped.map(_ + _) // Put it all together

(2) The weights do change, but by a linear scaling factor as if they represent signed distances along a line. Then we let (d1-a)*x1 + (d2-a)*x2 + ... + (dn-a)*xn = y be our previous answer, assuming that we are at a; then if we move to b we can modify this as (d1-b)*x1... = (d1-a+a-b)*x1+... = (d1-a)*x1+(a-b)*x1+... which shows that we just need the sums of the x values and a single distance to get the new answer from our old ones. So:

val xs = List(1,2,3,4,5)
val ds = List(3,2,5,1,4)              // Treat these as distances along a line
// Desired:
  // 1
  // (3-2)*1 + 2
  // (3-5)*1 + (2-5)*2 + 3
  // (3-1)*1 + (2-1)*2 + (5-1)*3 + 4
  // (3-4)*1 + (2-4)*2 + (5-4)*3 + (1-4)*4 + 5
val ws = ds.map(_ - ds.head)          // Distances from the first element
val mul = (xs,ws).zipped.map(_ * _)
val cuml = mul.scanLeft(0)(_ + _)
// If we used this alone we would get:
  // 1
  // (3-3)*1 + 2            <-- should be subtracting 2, not 3!
  // (3-3)*1 + (2-3)*2 + 3  <-- should be subtracting 5, not 3!
  // etc.
val cumlx = xs.scanLeft(0)(_ + _)             // Need this to fix up our sums
val fix = (cumlx,ws).zipped.map(-1 * _ * _)   // This will actually do it
val ans = (xs,cuml,fix).zipped.map(_ + _ + _)

The best way to understand how this works is to take it apart statement by statement and write things out by hand to verify that it is actually computing what we want it to compute.

(3) The weights change in no consistent manner as you advance. Distances to points in a plane tend to have that property, since the nonlinearity of the square root basically means that you have to calculate each one over again. So you just have to do the whole calculation each time.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文