代码之家  ›  专栏  ›  技术社区  ›  uray

任意数据类型比率转换器

  •  -1
  • uray  · 技术社区  · 16 年前

    我有以下代码:

    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=int O=float 带函数默认参数:

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

    线 double(inpMaxLevel - inpMinLevel) 结果是-1.0,我期望它在浮点中是4294967295。

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

    2 回复  |  直到 7 年前
        1
  •  0
  •   jbernadas    16 年前

    除了在强制转换之前将所有值强制转换为双精度值以防止溢出之外,当下限大于0时,您的代码返回错误的结果,因为您没有适当地调整值。这个想法是把范围[以分钟为单位,以最大值为单位]映射到范围[以分钟为单位,以最大值为单位],所以:

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

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

    • 将范围[以分钟为单位,以分钟为单位]映射到[0,以分钟为单位,以分钟为单位]。要做到这一点,从x减去以_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]。要执行此操作,请将“最小值”添加到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],结果如下:

    • 转换比(-1.0,-1.0,1.0,3.0,2.0)=3.0
    • 转换比(-0.8,-1.0,1.0,3.0,2.0)=2.9
    • 换算比(0.8,-1.0,1.0,3.0,2.0)=2.1
    • 换算比(1.0,-1.0,1.0,3.0,2.0)=2.0

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

        2
  •  0
  •   Roman Starkov    16 年前

    尝试

    (double) inpMaxLevel - (double) inpMinLevel
    

    相反。你现在做的是从最小值减去最大值。 数字仍为int类型 -它必然溢出;有符号int从根本上无法表示其最小值和最大值之间的差异。