从非均匀范围转换浮点数

Posted

技术标签:

【中文标题】从非均匀范围转换浮点数【英文标题】: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。 我的解决方案只依赖于输入“重叠”,输出和输入的关系并不重要 【参考方案1】:

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

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

将范围推入数组/一些标准集合 使用排序http://www.cplusplus.com/reference/algorithm/sort/. 要进行比较,请仅使用输入范围的最小值或最大值。 使用最小值或最大值查询范围(对应如上)

替代方法

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

转换这个:-

 -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> f8.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) 复杂度。

【讨论】:

以上是关于从非均匀范围转换浮点数的主要内容,如果未能解决你的问题,请参考以下文章

将范围-1到1的浮点数转换为短的快速方法?

frame的数值如果是浮点数,该怎么取舍只保留小数点后1位

用脚编码音频:将 32 位浮点数转换为 mp3

ieee754单精度浮点数 表示方法

H. 浮点数

将 24 位值转换为浮点数并返回