1

I have 2 double values which can go from let's say start value 62.243 to end value 79.495. I have another 2 double values which can go from let's say start value 4.456 to end value 7.687.

double start_1 = 62.243;
double end_1 = 79.495;

double start_2 = 4.456;
double end_2 = 7.687;

Now if I a value picked between start_1 and end_1, I want to interpolate the same value to a value between start_2 and end_2.

Question:
How do implement the below function in C++ which can do what I described above?

double InterpolateAValue(const double start_1, const double end_1, const double start_2, const double end_2, double value_between_start_1_and_end_1) {
     // How to get a value between start_2 and end_2 which matches the position of value_between_start_1_and_end_1 in the range of `start_1` and `end_1`
};

I think above function should pass the following unit test.

EXPECT_DOUBLE_EQ(40.0, InterpolateAValue(10.0, 20.0, 30.0, 50.0, 15.0));

std::lerp seems to be doing something like what I need but not exactly. I am on C++11. I have taken double as the type here. I could have chosen floats as well but a wish to see how doubles affect the math is also a part of the question.

TheWaterProgrammer
  • 7,055
  • 12
  • 70
  • 159
  • Be careful, mods could mark this as [a duplicate](https://stackoverflow.com/a/5735770/10141528) – Leif Messinger LOAF Jun 14 '21 at 16:53
  • 2
    I find it useful to think about it as a two-step process: first calculate the percentage of the distance of your point p between s1 and e1 (normalized so it’s a double between 0. And 1., with 0.0 meaning p=s1, 1.0 meaning p=s2, 0.5 meaning it’s halfway between them, etc); then calculate the distance between s2 and e2, multiply that by your normalized-percentage, and add the result to s2. – Jeremy Friesner Jun 14 '21 at 16:56
  • @JeremyFriesner Yes. That makes a lot of sense. I felt it's such a common need. There must be a question on SO which answers exactly this need. – TheWaterProgrammer Jun 14 '21 at 16:58
  • Reference implementation in python: https://stackoverflow.com/a/1969274 – Nick is tired Jun 14 '21 at 17:02
  • [this post](https://stackoverflow.com/questions/5731863/mapping-a-numeric-range-onto-another/5735770#5735770) has the answer to my question @LeifMessingerLOAF. But does that technique work for doubles as well? I mean doubles precision would not be an issue? I guess it should work for doubles as well but wish to confirm – TheWaterProgrammer Jun 14 '21 at 17:03
  • 2
    I don't understand why `InterpolateAValue(10.0, 20.0, 30.0, 50.0, 5.0)` should be `40.0`. Should the last argument be `15.0`? – Nathan Pierson Jun 14 '21 at 17:04
  • @NathanPierson Ah yes. Sorry. The last argument should be `15.0`. I corrected the question. – TheWaterProgrammer Jun 14 '21 at 17:06

2 Answers2

4

Since C++20 there is std::lerp.

Computes a+t(b−a), i.e. the linear interpolation between a and b for the parameter t (or extrapolation, when t is outside the range [0,1]).

It does half of what you want. Your t is t = ( value - start_1) / (end_1 - start_1). Hence you can do

#include <cmath>

double InterpolateAValue(double start_1,double end_1,double start_2, const double end_2, double value) {
    return std::lerp(start_2, end_2, (value - start1) / (end_1 - start_1));
}
463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
3

For a number value_between_start_1_and_end_1,

lambda = (value_between_start_1_and_end_1 - start_1) / (end_1 - start_1)

tells you how far you are along the 1-line. 0 means you're at start_1, 1 means you're at end_1.

Then use

start_2 + lambda * (end_2 - start_2)

to get the corresponding position along the 2-line. I've separated the computation into two stages, but aside from giving up ease of debugging, you could combine in one step.

Personally I'd always use doubles for this. A float could even be slower on modern systems due to unexpected type conversions. Of course you need to check that start_1 and end_1 are different.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483