【问题标题】:arbitrary datatype ratio converter任意数据类型比率转换器
【发布时间】:2010-08-02 11:53:03
【问题描述】:

我有以下代码:

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。

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

【问题讨论】:

  • 如果我没记错的话numeric_limits&lt;int&gt;::min()numeric_limits&lt;float&gt;::min() 的含义完全不同:对于浮点,它是最小的非零正值。我不明白如何将这两者混合并获得有意义的东西。
  • 是的,如果 T 是浮点数,那么用户应该覆盖默认值

标签: c++ templates math numeric


【解决方案1】:

添加到 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(否则,所有输入将映射到同一点)。为防止舍入错误,请尽量不要使用小范围。

【讨论】:

    【解决方案2】:

    试试

    (double) inpMaxLevel - (double) inpMinLevel
    

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

    【讨论】:

    • @uray - 仔细观察,不会发生溢出,因为据我所知,没有其他数字类型可以溢出双精度数。至于舍入错误 - 我不确定,抱歉。
    猜你喜欢
    • 2023-03-17
    • 1970-01-01
    • 1970-01-01
    • 2016-07-28
    • 2020-03-16
    • 2023-04-05
    • 1970-01-01
    • 1970-01-01
    • 2019-05-26
    相关资源
    最近更新 更多