【问题标题】:Convert float number from nonuniform ranges从非均匀范围转换浮点数
【发布时间】:2017-04-01 02:57:31
【问题描述】:

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

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

 {-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}

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

有人知道比线性搜索更好的解决方案吗?或者是否已经存在执行这种转换的容器?

非常感谢。

【问题讨论】:

  • 范围可以重叠吗?
  • @user1034749 不,它们不重叠。
  • @user1034749:更正 - 输入集或输出集中的范围不重叠。但是,不幸的是,输入和输出的范围确实如此。 IE。 {-30.0, -20.0} 转换为 {-25.0, -20.0}。
  • 我的解决方案只依赖于输入“重叠”,输出和输入的关系并不重要

标签: c++ c++11


【解决方案1】:

我假设范围不能重叠。 (域和范围)

我建议对范围进行排序。
这样,您可以使用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)

【讨论】:

    【解决方案2】:

    作为@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";
        }
    }
    

    【讨论】:

    • 非常优雅的解决方案。 (1)unordered_map可以用吗? (2) 抱歉,我误解了您的“非重叠”问题。不幸的是,from->to 范围可以重叠。
    【解决方案3】:

    这是对@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) 复杂度。

    【讨论】:

      猜你喜欢
      • 2011-07-16
      • 1970-01-01
      • 1970-01-01
      • 2011-04-04
      • 2013-06-21
      • 1970-01-01
      • 2020-04-04
      • 2020-09-07
      • 1970-01-01
      相关资源
      最近更新 更多