C语言 将数字范围映射到另一个

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5731863/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 08:26:48  来源:igfitidea点击:

Mapping a numeric range onto another

cmatharduino

提问by Joe

Math was never my strong suit in school :(

数学从来都不是我在学校里的强项:(

int input_start = 0; // The lowest number of the range input.
int input_end = 254; // The lowest number of the range input.
int output_start = 500; // The lowest number of the range output.
int output_end = 5500; // The largest number of the range ouput.

int input = 127; // Input value.
int output = 0;

How can I convert the input value to the corresponding output value of that range?

如何将输入值转换为该范围的相应输出值?

For example, an input value of "0" would equal an output value of "500", an input value of "254" would equal an output value of "5500". I can't figure out how to calculate an output value if an input value is say 50 or 101.

例如,输入值“0”将等于输出值“500”,输入值“254”将等于输出值“5500”。如果输入值是 50 或 101,我无法弄清楚如何计算输出值。

I'm sure it's simple, I can't think right now :)

我确定这很简单,我现在想不出来:)

Edit: I just need whole numbers, no fractions or anything.

编辑:我只需要整数,没有分数或任何东西。

回答by Alok Singhal

Let's forget the math and try to solve this intuitively.

让我们忘记数学并尝试直观地解决这个问题。

First, if we want to map input numbers in the range [0, x] to output range [0, y], we just need to scale by an appropriate amount. 0 goes to 0, xgoes to y, and a number twill go to (y/x)*t.

首先,如果我们想将范围 [ 0, x]中的输入数字映射到输出范围 [ 0, y] ,我们只需要按适当的量进行缩放。0 转到 0,x转到y,一个数字t将转到(y/x)*t

So, let's reduce your problem to the above simpler problem.

因此,让我们将您的问题简化为上述更简单的问题。

An input range of [input_start, input_end] has input_end - input_start + 1numbers. So it's equivalent to a range of [0, r], where r = input_end - input_start.

[ input_start, input_end]的输入范围有input_end - input_start + 1数字。所以它相当于一个范围 [ 0, r] ,其中r = input_end - input_start

Similarly, the output range is equivalent to [0, R], where R = output_end - output_start.

同样,输出范围等价于 [ 0, R] ,其中R = output_end - output_start

An input of inputis equivalent to x = input - input_start. This, from the first paragraph will translate to y = (R/r)*x. Then, we can translate the yvalue back to the original output range by adding output_start: output = output_start + y.

的输入input等价于x = input - input_start。这,从第一段将转换为y = (R/r)*x. 然后,我们可以y通过添加output_start:将值转换回原始输出范围output = output_start + y

This gives us:

这给了我们:

output = output_start + ((output_end - output_start) / (input_end - input_start)) * (input - input_start)

Or, another way:

或者,另一种方式:

/* Note, "slope" below is a constant for given numbers, so if you are calculating
   a lot of output values, it makes sense to calculate it once.  It also makes
   understanding the code easier */
slope = (output_end - output_start) / (input_end - input_start)
output = output_start + slope * (input - input_start)

Now, this being C, and division in C truncates, you should try to get a more accurate answer by calculating things in floating-point:

现在,这是 C,而 C 中的除法会截断,您应该尝试通过计算浮点数来获得更准确的答案:

double slope = 1.0 * (output_end - output_start) / (input_end - input_start)
output = output_start + slope * (input - input_start)

If wanted to be even more correct, you would do a rounding instead of truncation in the final step. You can do this by writing a simple roundfunction:

如果想要更正确,您可以在最后一步进行四舍五入而不是截断。您可以通过编写一个简单的round函数来做到这一点:

#include <math.h>
double round(double d)
{
    return floor(d + 0.5);
}

Then:

然后:

output = output_start + round(slope * (input - input_start))

回答by Dustin

Arduino has this built-in as map.

Arduino 将这个内置为map

Example:

例子:

/* Map an analog value to 8 bits (0 to 255) */
void setup() {}

void loop()
{
  int val = analogRead(0);
  val = map(val, 0, 1023, 0, 255);
  analogWrite(9, val);
}

It also has the implementation on that page:

它还在该页面上有实现:

long map(long x, long in_min, long in_max, long out_min, long out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

回答by Erti-Chris Eelmaa

the formula is

公式是

f(x) = (x - input_start) / (input_end - input_start) * (output_end - output_start) + output_start

f(x) = (x - input_start) / (input_end - input_start) * (output_end - output_start) + output_start

I'll hook up this post here: https://betterexplained.com/articles/rethinking-arithmetic-a-visual-guide/as it helped me a lot when trying to come up with this intuitively. Once you understand what the post is saying, it's trivial to come up with these formulas on your own. Note that I used to struggle with such questions as well. (I have no affiliations - just found it very useful)

我将在此处连接这篇文章:https: //betterexplained.com/articles/rethinking-arithmetic-a-visual-guide/因为它在尝试直观地提出这个问题时对我帮助很大。一旦你理解了帖子的内容,你自己想出这些公式就很简单了。请注意,我过去也曾为这些问题而苦恼。(我没有从属关系 - 只是发现它非常有用)

say you have range [input_start..input_end], let's start by normalising it such that 0 is input_start, and 1 is input_end. this is simple technique to make the problem easier.

假设您有 range [input_start..input_end],让我们首先对其进行标准化,以便 0 是input_start,1 是input_end。这是使问题更容易的简单技术。

how do we do that? we'll, we'd have to shift everything left by input_start amount, such that if input x happens to be input_start, it should give zero.

我们怎么做?我们会,我们必须将所有东西向左移动 input_start 数量,这样如果输入 x 恰好是input_start,它应该给出零。

so, let's say f(x)is the function that does the conversion.

所以,让我们说f(x)是进行转换的函数。

f(x) = x - input_start

let's try it:

让我们试试看:

f(input_start) = input_start - input_start = 0

works for input_start.

input_start.

at this point, it does not work for input_endyet, as we have not scaled it.

在这一点上,它还不起作用input_end,因为我们还没有对其进行缩放。

let's just scale it down by the length of the range, then we'll have the biggest value (input_end) mapped to one.

让我们按范围的长度缩小它,然后我们将最大的值 (input_end) 映射到 1。

f(x) = (x - input_start) / (input_end - input_start)

ok, let's give it a try with input_end.

好的,让我们试试看input_end

f(input_end) = (input_end - input_start) / (input_end - input_start) = 1

F(input_end) = (input_end - input_start) / (input_end - input_start) = 1

awesome, seems to work.

真棒,似乎工作。

okay, next step, we'll actually scale it to output range. It is as trivial as just multiplying with the actual length of the output range, as such:

好的,下一步,我们将实际将其缩放到输出范围。它就像乘以输出范围的实际长度一样微不足道,如下所示:

f(x) = (x - input_start) / (input_end - input_start) * (output_end - output_start)

now, actually, we're almost done, we just have to shift it to right so that 0 starts from output_start.

现在,实际上,我们几乎完成了,我们只需将它向右移动,以便 0 从 output_start 开始。

f(x) = (x - input_start) / (input_end - input_start) * (output_end - output_start) + output_start

let's give it a quick try.

让我们快速尝试一下。

f(input_start) = (input_start - input_start) / (input_end - input_start) * (output_end - output_start) + output_start

you see that the first part of equation is pretty much multiplied by zero, thus cancelling everything out, giving you

你看到方程的第一部分几乎乘以零,从而抵消了一切,给你

f(input_start) = output_start

let's try input_endas well.

我们也试试input_end

f(input_end) = (input_end - input_start) / (input_end - input_start) * (output_end - output_start) + output_start

which in turn will end up as:

最终将成为:

f(input_end) = output_end - output_start + output_start = output_end

as you can see, it now seems to be mapped correctly.

如您所见,它现在似乎已正确映射。

回答by Sven Marnach

The crucial point here is to do the integer division (which includes rounding) at the right place. None of the answers so far got the parentheses right. Here is the right way:

这里的关键点是在正确的位置进行整数除法(包括舍入)。到目前为止,没有一个答案是正确的。这是正确的方法:

int input_range = input_end - input_start;
int output_range = output_end - output_start;

output = (input - input_start)*output_range / input_range + output_start;

回答by QuantumMechanic

output = ((input - input_start)/(input_end - input_start)) * (output_end - output_start) + output_start

What that does is find out proportionally "how far into" the input range the input is. It then applies that proportion to the size of the output range to find out in absolute terms how far into the output range the output should be. It then adds the start of the output range to get the actual output number.

这样做是按比例找出输入“进入”输入范围的“多远”。然后将该比例应用于输出范围的大小,以绝对方式找出输出应该在输出范围内的距离。然后添加输出范围的开始以获取实际输出编号。