任意数据类型比率转换器

发布于 2024-09-12 10:18:23 字数 991 浏览 5 评论 0原文

我有以下代码:

template<typename I,typename O> O convertRatio(I input,
    I inpMinLevel = std::numeric_limits<I>::min(),
    I inpMaxLevel = std::numeric_limits<I>::max(),
    O outMinLevel = std::numeric_limits<O>::min(),
    O outMaxLevel = std::numeric_limits<O>::max() )
{
    double inpRange = abs(double(inpMaxLevel - inpMinLevel));
    double outRange = abs(double(outMaxLevel - outMinLevel));
    double level    = double(input)/inpRange;
    return O(outRange*level);
}

用法是这样的:

 int value = convertRatio<float,int,-1.0f,1.0f>(0.5); 
 //value is around 1073741823 ( a quarter range of signed int)

问题是带有函数默认参数的 I=intO=float

 float value = convertRatio<int,float>(123456); 

double(inpMaxLevel - inpMinLevel) 结果是-1.0,我预计它的浮点数为 4294967295。

你有什么想法可以做得更好吗? 基本思想是将值从一个范围转换为另一个具有不同数据类型可能性的范围。

I have following code:

template<typename I,typename O> O convertRatio(I input,
    I inpMinLevel = std::numeric_limits<I>::min(),
    I inpMaxLevel = std::numeric_limits<I>::max(),
    O outMinLevel = std::numeric_limits<O>::min(),
    O outMaxLevel = std::numeric_limits<O>::max() )
{
    double inpRange = abs(double(inpMaxLevel - inpMinLevel));
    double outRange = abs(double(outMaxLevel - outMinLevel));
    double level    = double(input)/inpRange;
    return O(outRange*level);
}

the usage is something like this:

 int value = convertRatio<float,int,-1.0f,1.0f>(0.5); 
 //value is around 1073741823 ( a quarter range of signed int)

the problem is for I=int and O=float with function default parameter:

 float value = convertRatio<int,float>(123456); 

the line double(inpMaxLevel - inpMinLevel) result is -1.0, and I expect it to be 4294967295 in float.

do you have any idea to do it better?
the base idea is just to convert a value from a range to another range with posibility of different data type.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

要走就滚别墨迹 2024-09-19 10:18:23

添加到 romkyns 答案中,除了在转换之前将所有值转换为双精度数以防止溢出之外,当下限不同于 0 时,您的代码会返回错误的结果,因为您没有适当地调整值。这个想法是将范围 [in_min, in_max] 映射到范围 [out_min, out_max],因此:

  • f(in_min) = out_min
  • f(in_max) = out_max

令 x 为要映射的值。该算法类似于:

  • 将范围 [in_min, in_max] 映射到 [0, in_max - in_min]。为此,请从 x 中减去 in_min。
  • 将范围 [0, in_max - in_min] 映射到 [0, 1]。为此,请将 x 除以 (in_max - in_min)。
  • 将范围 [0, 1] 映射到 [0, out_max - out_min]。为此,请将 x 乘以 (out_max - out_min)。
  • 将范围 [0, out_max - out_min] 映射到 [out_min, out_max]。为此,请将 out_min 添加到 x。

下面的 C++ 实现就是这样做的(我会忘记默认值以使代码更清晰:

template <class I, class O>
O convertRatio(I x, I in_min, I in_max, O out_min, O out_max) {
  const double t = ((double)x - (double)in_min) /
                   ((double)in_max - (double)in_min);
  const double res = t * ((double)out_max - (double)out_min) + out_min;
  return O(res);
}

请注意,我没有采用范围大小的绝对值。这允许反向映射。例如,它可以映射 [- 1.0, 1.0] 到 [3.0, 2.0],得到以下结果:

  • convertRatio(-1.0, -1.0, 1.0, 3.0, 2.0) = 3.0
  • ConvertRatio(-0.8, -1.0, 1.0, 3.0, 2.0) = 2.9
  • ConvertRatio( 0.8, -1.0, 1.0, 3.0, 2.0) = 2.1
  • convertRatio(1.0, -1.0, 1.0, 3.0, 2.0) = 2.0

唯一需要的条件是 in_min != in_max (防止被零除)和 out_min != out_max (否则,所有输入将映射到同一点)。为防止舍入错误,请尽量不要使用小范围。

Adding to romkyns answer, besides casting all values to doubles before casting to prevent overflows, your code returns wrong results when the lower bounds are distinct than 0, because you don't adjust the values appropiately. The idea is mapping the range [in_min, in_max] to the range [out_min, out_max], so:

  • f(in_min) = out_min
  • f(in_max) = out_max

Let x be the value to map. The algorithm is something like:

  • Map the range [in_min, in_max] to [0, in_max - in_min]. To do this, substract in_min from x.
  • Map the range [0, in_max - in_min] to [0, 1]. To do this, divide x by (in_max - in_min).
  • Map the range [0, 1] to [0, out_max - out_min]. To do this, multiply x by (out_max - out_min).
  • Map the range [0, out_max - out_min] to [out_min, out_max]. To do this, add out_min to x.

The following implementation in C++ does this (I will forget the default values to make the code clearer:

template <class I, class O>
O convertRatio(I x, I in_min, I in_max, O out_min, O out_max) {
  const double t = ((double)x - (double)in_min) /
                   ((double)in_max - (double)in_min);
  const double res = t * ((double)out_max - (double)out_min) + out_min;
  return O(res);
}

Notice that I didn't took the absolute value of the range sizes. This allows reverse mapping. For example, it makes possible to map [-1.0, 1.0] to [3.0, 2.0], giving the following results:

  • convertRatio(-1.0, -1.0, 1.0, 3.0, 2.0) = 3.0
  • convertRatio(-0.8, -1.0, 1.0, 3.0, 2.0) = 2.9
  • convertRatio(0.8, -1.0, 1.0, 3.0, 2.0) = 2.1
  • convertRatio(1.0, -1.0, 1.0, 3.0, 2.0) = 2.0

The only condition needed is that in_min != in_max (to prevent division by zero) and out_min != out_max (otherwise, all inputs will be mapped to the same point). To prevent rounding errors, try to not use small ranges.

虐人心 2024-09-19 10:18:23

尝试

(double) inpMaxLevel - (double) inpMinLevel

一下。您当前正在做的事情是从 min 中减去 max ,而数字仍然是 int 类型 - 这必然会溢出;有符号 int 根本上无法表示其最小值和最大值之间的差异。

Try

(double) inpMaxLevel - (double) inpMinLevel

instead. What you are doing currently is subtracting max from min while the numbers are still of type int - which necessarily overflows; a signed int is fundamentally incapable of representing the difference between its min and max.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文