Marnix
Marnix

Reputation: 6547

Normalize a vector with one fixed value

I have this problem where I want to keep a list of values and normalize them so that the sum of all values is 1.

I found this question, but there is one difference. I would like to have 1 value that is fixed. Because, there are 4 GUI sliders and I drag one. The other 3 should update accordingly so that the total sum is 1.

// Let's keep 0.6 fixed and try to normalize the rest
List<float> categories = new List<float>() { 0.6f,0.3f,0.25f,0.25f };

// find the max value of the rest of the values that is not the fixed number
float maxval = categories.Where(s => s != 0.6f).Max();

if (maxval != 0) // check if not all other 
{
    // calculate the ratio
    float ratio = (1 - 0.6f) / maxval;

    foreach (float s in categories)
    {
        if (s != 0.6f)
        {
            s *= ratio;
        }
    }
}
else // all values are 0, so just add the rest value
{
    // do something else that is correct
}

Unfortunately this example will return:

{ 0.6f, 0.4f, 0.33f, 0.33f } => sum is 1.66f

And there is something that I'm misunderstanding. Can someone give me a clue on how to get the rest of the values normalized to the rest sum (0.4f) so that the total sum of all values is 1?

Upvotes: 2

Views: 717

Answers (2)

Ben Voigt
Ben Voigt

Reputation: 283614

Among other problems, this loop doesn't do what you expect:

foreach (float s in categories) {
    if (s != 0.6f) {
        s *= ratio;
    }
}

s is a local copy of one of the values from categories. You modify the copy, and then it goes out of scope and your new value disappears. You never modified categories.

C# foreach cannot be used to modify a collection.

Furthermore, to avoid accumulating large rounding error, you should store to a new collection and not replace the values in categories, at least until the drag operation ends.

Upvotes: 0

SinisterMJ
SinisterMJ

Reputation: 3509

You are calculating it wrongly.

If you have a 4 elements, and 1 of those is fixed, and the total sum needs to be 1, you would go like:

ratio = (1-fixedElement) / sumOfAllOtherElements;

EachNonFixedElement *= ratio;

You are calculating the ratio just with the max value, but you need to calculate it with the sum of all non-fixed elements.

Upvotes: 6

Related Questions