Elegant.Scripting
Elegant.Scripting

Reputation: 837

How to calculate relative percentage (apply score to a new range)?

I'm a front-end and back-end developer, and something that I've come across a few times when dealing with simple game development and animation is this challenge. I wish I had a function to solve for this, so I was hoping you math guys/gals could help me out with the pseudocode, and then I could post a function that we can run via the browser to test it.

It's a little hard for me to explain the challenge, so forgive me, I'm going to give it out like a riddle:

You're trying to find your test score as a percent. You know that for a normal percent, expressed as a decimal from 0.00 - 1.00, you'd do something like actual_test_score / max_test_score.

However, you're not looking for any old percent. You'd like to express your percent as a decimal within a specified range of decimal numbers. For example, you'd like (given an actual_test_score and a max_test_score) to get your test score as a percent from 0.50 - 1.00.

How can you calculate actual_test_score / max_test_score expressed as a percentage between a range of 0.50 - 1.00, instead of your typical range that is 0.00 - 1.00.

It took kind of a while to explain this (and it might not be the best explanation) because it's not something I have to explain often, but again it's something I run into every now and then.

Upvotes: 0

Views: 1547

Answers (2)

Phil H
Phil H

Reputation: 20151

This is a linear range mapping from [0,1] to [newMin,newMax], which is a specific case of the general linear range mapping from [oldMin,oldMax] to [newMin,newMax]:

function linearRemap(value, oldMin, oldMax, newMin, newMax) {
    var newScale = newMax - newMin;
    var valueAsPct = (val - oldMin) / (oldMax - oldMin);
    var scaledValue = valueAsPct * newScale;
    var shiftedAndScaledValue = scaledValue + newMin;
    return shiftedAndScaledValue;
}

So the limited case here permits you to skip the percent calculation line:

function linearRemapPct(valueAsPct, newMin, newMax) {
    var newScale = newMax - newMin;
    var scaledValue = valueAsPct * newScale;
    var shiftedAndScaledValue = scaledValue + newMin;
    return shiftedAndScaledValue;
}

Or just

function linearRemapPct(valueAsPct, newMin, newMax) {
    return (valueAsPct * (newMax - newMin) + newMin);
}

If you want to have something that's a bit more careful about loss of precision:

function linearRemapPct(valueAsPct, newMin, newMax) {
    return (valueAsPct * newMax) + (1 - valueAsPct) * newMin;
}

Upvotes: 3

Shadow
Shadow

Reputation: 9427

If I'm reading this correctly, would you want 0 to be expressed as 0.5?

In that case, you would need to multiply your number by the range of the score; highest_score - lowest_score which in your case appears to be 1 - 0.5. Then add the lowest_score to your result.

Here is an example in the form of a rough function;

function relative_percentage (score, max_score, min_score) {
    // score should be a value from 0 to 1.
    return score * (max_score - min_score) + min_score;
}

Upvotes: 0

Related Questions