任意数据类型比率转换器

时间:2010-08-02 11:53:03

标签: c++ templates math numeric

我有以下代码:

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。

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

2 个答案:

答案 0 :(得分:0)

尝试

(double) inpMaxLevel - (double) inpMinLevel

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

答案 1 :(得分:0)

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