我需要将一组数字从一个范围转换为另一个范围,同时保持值的相对分布。
例如,可以缩放包含随机生成的浮点数的向量以适合可能的无符号字符值 (0..255)。忽略类型转换,这意味着无论提供什么输入(例如 -1.0 到 1.0),所有数字都将缩放到 0.0 到 255.0(或大约)。
我创建了一个模板类来执行此转换,可以使用以下方法将其应用于集合std::transform
:
template <class TYPE>
class scale_value {
const TYPE fmin, tmin, ratio;
public:
TYPE operator()(const TYPE& v) {
TYPE vv(v);
vv += (TYPE(0) - fmin); // offset according to input minimum
vv *= ratio; // apply the scaling factor
vv -= (TYPE(0) - tmin); // offset according to output minimum
return vv;
}
// constructor takes input min,max and output min,max
scale_value(const TYPE& pfmin, const TYPE& pfmax, const TYPE& ptmin, const TYPE& ptmax)
: fmin(pfmin), tmin(ptmin), ratio((ptmax-tmin)/(pfmax-fmin)) { }
// some code removed for brevity
};
但是,上述代码仅适用于实数(float
, double
, ...)。整数在按比例放大时起作用,但即使这样也只能按整数比率:
float scale_test_float[] = {0.0, 0.5, 1.0, 1.5, 2.0};
int scale_test_int[] = {0, 5, 10, 15, 20};
// create up-scalers
scale_value<float> scale_up_float(0.0, 2.0, 100.0, 200.0);
scale_value<int> scale_up_int(0, 20, 100, 200);
// create down-scalers
scale_value<float> scale_down_float(100.0, 200.0, 0.0, 2.0);
scale_value<int> scale_down_int(100, 200, 0, 20);
std::transform(scale_test_float, scale_test_float+5, scale_test_float, scale_up_float);
// scale_test_float -> 100.0, 125.0, 150.0, 175.0, 200.0
std::transform(scale_test_int, scale_test_int+5, scale_test_int, scale_up_int);
// scale_test_int -> 100, 125, 150, 175, 200
std::transform(scale_test_float, scale_test_float+5, scale_test_float, scale_down_float);
// scale_test_float -> 0.0, 0.5, 1.0, 1.5, 2.0
std::transform(scale_test_int, scale_test_int+5, scale_test_int, scale_down_int);
// scale_test_int -> 0, 0, 0, 0, 0 : fails due to ratio being rounded to 0
我目前对此问题的解决方案是将内部的所有内容存储scale_value
为 a double
,并根据需要使用类型转换:
TYPE operator()(const TYPE& v) {
double vv(static_cast<double>(v));
vv += (0.0 - fmin); // offset according to input minimum
vv *= ratio; // apply the scaling factor
vv -= (0.0 - tmin); // offset according to output minimum
return static_cast<TYPE>(vv);
}
这适用于大多数情况,尽管整数有一些错误,因为值被截断而不是四舍五入。例如{0,5,10,15,20}
从0..20
to缩放20..35
,然后返回给{0,4,9,14,20}
.
所以,我的问题是,有没有更好的方法来做到这一点?在缩放float
s 集合的情况下,类型转换似乎相当多余,而在缩放int
s 时,由于截断而引入了错误。
顺便说一句,我很惊讶没有发现一些东西(至少,没有什么明显的)来提升这个目的。也许我错过了 - 各种数学库让我感到困惑。
编辑:我意识到我可以专注operator()
于特定类型,但这意味着大量的代码重复,这会破坏模板的有用部分之一。除非有一种方法可以对所有非浮点类型(short、int、uint、...)进行一次专门化。