由于零而总是将滑块累加到100%失败的算法

Sea*_*ean 1 algorithm xcode ios swift

这是(应该是)一个函数,它确保多个滑块值之和总是相加globalTotal.

用户可以手动更改滑块值changer.value,然后将此功能应用于其他滑块的值时,可以确定它们的新值或endVal.

startVal需要改变的滑块和改变的滑块的原始值,changerStartVal并且可以通过加权确定其他的新值.

问题和我的问题是.有时remainingStartVals可以为零(当滑块更改一直移动到最大值时)或者startVal可以为零(当滑块更改移动到零然后移动另一个滑块时).当发生这种情况时,我分别得到除零或乘零.这两个都很糟糕,导致不正确的结果.有没有一种简单的方法来解决这个问题?

func calcNewVal(startVal: Float, changerStartVal: Float) -> Float {

    let remainingStartVals = globalTotal - changerStartVal

    let remainingNewVals = globalTotal - changer.value

    let endVal = ((startVal * (100 / remainingStartVals)) / 100) * remainingNewVals

    return endVal

}
Run Code Online (Sandbox Code Playgroud)

Mis*_*cha 5

这是一个数学问题,不是与Swift或任何特定编程语言相关的问题,所以我将用数学公式和解释而不是代码片段来回答.

我也不太了解你的算法.例如,在这一行:

let endVal = ((startVal * (100 / remainingStartVals)) / 100) * remainingNewVals
Run Code Online (Sandbox Code Playgroud)

你首先乘以100然后除以100,这样你就可以把所有这100个因子排除在外!


但是,我想我理解你想要实现的目标,问题没有通用的解决方案.在编写算法之前,您必须准确定义您希望它的行为方式,包括所有边缘情况.

我们来定义:

  • v i作为第 i个滑块的值
  • Δ 作为变化个滑块的值

然后你必须考虑以下情况:


情况1:

0 <V ≤1对于所有的滑块(比你改变了一个其他)

这可能是您正在考虑的常见情况.在这种情况下,你想使自己的总变化等于变化调整滑块不变的值Δ 改变你改变滑块.换一种说法:

Σ Δ = 0

如果您有3个滑块,则减少为:

  • Δ 123 = 0

如果更改的滑块是i = 1的滑块,那么此要求将为:

  • Δ 1 = - (Δ 23)

你想滑块来调整比例,这意味着这种变化Δ 1不应该等同于其他滑块分布的,而是取决于他们的当前值:

  • Δ 2 = -瓦特21
  • Δ 3 = -瓦特31

规范权重因子是

  • w 2 = v 2 /(v 2 + v 3)
  • w 3 = v 3 /(v 2 + v 3)

因此我们得到:

  • Δ 2 = - v 2 /(V 2 + V 3)*Δ 1
  • Δ 3 = - v 3 /(V 2 + V 3)*Δ 1

所以这些是适用于这种特殊情况的公式.

但是,还有很多其他情况不适合这种方法:


案例2:

对于至少一个但不是所有滑块(除了您更改的滑块之外), v i = 0

在这种情况下,案例1的方法仍然可行(加上它将是合乎逻辑的事情).但是,如果滑块的值为零,则它永远不会改变.所有更改将分布在滑块上,值大于0.


案例3:

对于所有滑块(除了您更改的滑块之外), v i = 0

在这种情况下,比例变化不起作用,因为根本没有信息如何在滑块上分配变化.他们都是零!这实际上是你的零分割问题:在我们有3个滑块并且滑块1改变的情况下,我们将得到

v 2 + v 3 = 0

这只是权重因子w i简单未定义的另一个表现.因此,您必须手动定义在这种情况下会发生什么.

在这种情况下,最合理的做法是将更改均匀分布在所有滑块上:

Δ = - (1/N)*Δ 1

其中n滑块数量(不包括已更改的滑块!).有了这个逻辑,每个滑块都会获得变化的"相同份额".


现在我们已经清楚了解我们的算法,您可以在代码中实现这些情况.这里以一些伪代码为例:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,您必须在开始时缓存滑块的当前状态值,或者(甚至更好)首先计算所有更改,然后批量应用所有更改.否则,您将使用刚刚计算的值v 2 '来确定值v 3 ',这显然会导致值不正确.