这是一个数学问题,而不是与 Swift 或任何特定编程语言相关的问题,因此我将用数学公式和解释而不是代码片段来回答。
我也不太明白你的算法。例如在这一行中:
let endVal = ((startVal * (100 / remainingStartVals)) / 100) * remainingNewVals
您首先乘以 100,然后除以 100,因此您可以首先将所有这 100 个因数排除在外!
但是,我想我理解你想要实现的目标,问题是is没有通用的解决方案。在编写算法之前,您必须定义exactly你希望它如何表现,包括所有边缘情况.
让我们定义一下:
-
vi as the value of the i-th slider and
-
Δi as the change of the i-th slider's value
那么你必须考虑以下情况:
Case 1:
0 < vi ≤ 1 for all sliders (other than the one you changed)
This is probably the common case you were thinking about. In this case you want to adjust the values of your unchanged sliders so that their total change is equal to the change Δchanged of the slider you changed. In other words:
∑i Δi = 0
如果您有 3 个滑块,则这会减少为:
如果更改的滑块是带有i = 1那么这个要求将是:
You want the sliders to adjust proportionally which means that this change Δ1 should not be distributed equally on the other sliders but depending on their current value:
- Δ2 = – w2 * Δ1
- Δ3 = – w3 * Δ1
标准化权重因子为
-
w2 = v2 / (v2 + v3)
-
w3 = v3 / (v2 + v3)
由此我们得到:
- Δ2 = – v2 / (v2 + v3) * Δ1
- Δ3 = – v3 / (v2 + v3) * Δ1
这些是适用于这种特殊情况的公式。
但是,还有很多其他情况不适用于此方法:
Case 2:
vi = 0 for at least one, but not all of the sliders (other than the one you changed)
在这种情况下,方法来自case 1仍然有效(而且这是合乎逻辑的事情)。但是,如果滑块的值为零,则它的值永远不会改变。所有更改都将分布在值 > 0 的滑块上。
Case 3:
vi = 0 for all sliders (other than the one you changed)
在这种情况下,比例更改不起作用,因为根本没有信息如何在滑块上分配更改。他们都是零!这实际上是你的零除问题:如果我们有 3 个滑块并且滑块 1 发生变化,我们会得到
v2 + v3 = 0
This is only another manifestation of the fact that the weight factors wi are simply undefined. Thus, you'll have to manually define what will happen in this case.
在这种情况下,最合理的做法是分发更改evenly在所有滑块上:
Δi = – (1 / n) * Δ1
where n is the 滑块数量(不包括已更改的!)。按照这种逻辑,每个滑块都会获得“相同份额”的变化。
现在我们已经清楚了我们的算法,您可以在代码中实现这些情况。这里以一些伪代码为例:
if sum(valuesOfAllSlidersOtherThanTheSliderThatChanged) == 0 {
for allUnchangedSliders {
// distribute change evenly over the sliders
Δi = – (1 / n) * Δ_changedSlider
}
}
else {
for allUnchangedSliders {
// use weight factor to change proportionally
Δi = – v_i / ∑(v_i) * Δ_changedSlider
}
}
Please be aware that you must cache the values of the current state of your sliders at the beginning or (even better) first compute all the changes and then apply all the changes in a batch. Otherwise you will use a value v2' that you just computed for determining the value v3' which will obviously result in incorrect values.