从非均匀范围转换浮点数

时间:2017-04-01 02:57:31

标签: c++ c++11

所以我有这个相对简单的问题,并且想知道它的解决方案是否已经存在。

我必须将一个值从一个范围转换为另一个范围。如果只有一个范围,像这样:

 {-30.0, 30.0} -> {25.0, 50.0}

本来很容易。 但我有一组范围:

 {-30.0, -20.0} -> {25.0, 30.0}
 {-20.0,   0.0} -> {30.0, 40.0}
 {  0.0,  30.0} -> {40.0, 50.0}

一种解决方案是对每次访问进行线性搜索。 另一种解决方案是使范围具有相等的长度,以便可以直接映射输入值。

有谁知道比线性搜索解决方案更好?或者,如果已经存在执行此类转换的容器?

非常感谢。

3 个答案:

答案 0 :(得分:0)

我认为范围不能重叠。 (域名和范围)

我建议对范围进行排序 这样,您就可以使用O(log n)来查询范围。

替代方法

在某些输入模式中,这种方法可能是合适的: -

转换它: -

 {-30.0, -20.0} -> {25.0, 30.0}
 {-20.0,   0.0} -> {30.0, 40.0}
 {  0.0,  30.0} -> {40.0, 50.0}

更多制服: -

float [] inputRange =  {-30,-20, -10,0 ,10       ,20       ,30};
float [] outputRange = {25 ,30 ,*35*,40,*43.3333*,*43.6667*,50};
//* is a pre-calculated 

然后,您只能使用O(1)进行查询。

缺点: -

  • 浪费更多记忆
  • 输入必须对齐,其值不是很小。 (本案例= 10)

答案 1 :(得分:0)

当@javaLover回复时,而不是线性 - O(n)操作, 当n个范围时,你可以找到合适的范围O(log n) 操作,例如使用std::map

#include <utility>
#include <map>
#include <algorithm>
#include <iostream>

int main()
{
    using Range = std::pair<double, double>;
    struct RangeLess {
        bool operator()(const Range &a, const Range &b) const {
            return a.first < b.first && a.second < b.second;
        }
    };
    using RangeMap = std::map<Range, Range, RangeLess>;
    const RangeMap ranges_map = {
        {{-30.0, -20.0}, {25.0, 30.0}},
        {{-20.0, 0.0}, {30.0, 40.0}},
        { {1.0, 30.0}, {40.0, 50.0}},
    };
    auto map_point = [&ranges_map](double x) -> double {
        const Range x_range = {x, x};
        auto it = ranges_map.find(x_range);
        if (it == ranges_map.end()) {
            return x;
        } else {
            const Range &in = it->first;
            const Range &out = it->second;

            return (x - in.first) / (in.second - in.first) * (out.second - out.first) + out.first;
        }
    };

    const double patterns[] = {-40, -30, -25, -20, 0.5, 5, 40};
    for (auto &&x : patterns) {
        std::cout << x << " -> " << map_point(x) << "\n";
    }
}

答案 2 :(得分:0)

这是对user1034749提出的解决方案的详细说明。它使用std::set和一个包含两对值的类。

template<class SRC, class DST>
class Range {
 public:
  std::pair<SRC, SRC> src_range;
  std::pair<DST, DST> dst_range;

  bool operator<(const Range& rhs) const {
    return (src_range.first < rhs.src_range.first) && (src_range.second < rhs.src_range.second);
  }

  Range(SRC src_first, SRC src_second,
        DST dst_first, DST dst_second)
  : src_range(src_first, src_second),
    dst_range(dst_first, dst_second) {}

  Range()
  : src_range(0, 0),
    dst_range(0, 0) {}

  Range(SRC value)
  : src_range(value, value),
    dst_range(value, value) {}
};

bool mapping_test() {
  // Mapping
  std::set<Range<double,double>>
          z = {{-30.0, -20.0, -10.0, -5.0},
               {-20.0, 0, -5.0, 5.0},
               {0, 10.0, 5.0, 8.0}};

  // Find range that contains this value
  Range<double,double> f{8.0};

  auto d = z.find(f);
  if(d != z.end()) {
    std::cout << "Found {" << (*d).dst_range.first
                           << ","
                           << (*d).dst_range.second
                           << "}\n";
  }

  return true;
}

在这种情况下,可以找到相关值的范围,包括源范围和目标。 std::set容器中的查找是log(n)复杂度。