如果我们具有max..min值的具体范围,很容易将其标准化为0..1浮点值,但是如果我们没有具体限制?是否可以构建通用函数以使输出在0和1之间?在我看来,我认为这是不可能的,但我不是数学专家。
我正在寻找JavaScript或PHP的实现,但是C / C ++ / Python / Delphi上的任何代码都可以提供示例(如果有的话)
答案 0 :(得分:6)
有很多方法可以做到这一点。我将省略映射-inf
和+inf
,这可以使用条件语句完成。
答案 1 :(得分:1)
几乎所有的浮点数编程,都是以对数方式分布的。因此,首先取值的log()
开始映射,注意边缘情况问题。
double map(double x, double x0, double x1, double y0, double y1) {
return (x - x0) / (x1 - x0) * (y1 - y0) + y0;
}
double noramlize01(double x) {
assert(x == x); // fail is x is NaN
// These values only need to be calculated once.
double logxmin = log(DBL_TRUE_MIN); // e.g. -323.306...
double logxmax = log(DBL_MAX); // e.g. 308.254...
double y;
if (x < -DBL_MAX) y = 0.0;
else if (x < 0.0) {
y = map(log(-x), logxmax, logxmin, nextafter(0.0,1.0), nextafter(0.5,0.0));
} else if (x == 0.0) {
y = 0.5;
} else if (x <= DBL_MAX) {
y = map(log(x), logxmin, logxmax, nextafter(0.5,1.0), nextafter(1.0,0.5));
} else {
y = 1.0;
}
return y;
}
double round_n(double x, unsigned n) {
return x * n;
}
void testr(double x) {
printf("% 20e %#.17g\n", x, noramlize01(x));
//printf("% 20e %.17f\n", -x, noramlize01(-x));
}
int main(void) {
double t[] = {0.0, DBL_TRUE_MIN, DBL_MIN, 1/M_PI, 1/M_E,
1.0, M_E, M_PI, DBL_MAX, INFINITY};
for (unsigned i = sizeof t/sizeof t[0]; i > 0; i--) {
testr(-t[i-1]);
}
for (unsigned i = 0; i < sizeof t/sizeof t[0]; i++) {
testr(t[i]);
}
}
示例输出
-inf 0.0000000000000000
-1.797693e+308 4.9406564584124654e-324
-3.141593e+00 0.24364835649917244
-2.718282e+00 0.24369811843639441
-1.000000e+00 0.24404194470924687
-3.678794e-01 0.24438577098209935
-3.183099e-01 0.24443553291932130
-2.225074e-308 0.48760724499523350
-4.940656e-324 0.49999999999999994
-0.000000e+00 0.50000000000000000
0.000000e+00 0.50000000000000000
4.940656e-324 0.50000000000000011
2.225074e-308 0.51239275500476655
3.183099e-01 0.75556446708067870
3.678794e-01 0.75561422901790065
1.000000e+00 0.75595805529075311
2.718282e+00 0.75630188156360556
3.141593e+00 0.75635164350082751
1.797693e+308 0.99999999999999989
inf 1.0000000000000000
答案 2 :(得分:1)
如果你不介意比特步,并确信代码使用IEEE二进制64位浮点,那么一些快速代码只有少量的FP数学运算
// If double is 64-bit and same endian as integer
double noramlize01(double x) {
assert(x == x); // fail if x is NaN
union {
double d;
int64_t i64;
uint64_t u64;
} u = {x};
double d;
if (u.i64 < 0) {
u.u64 -= 0x8000000000000000;
d = (double) -u.i64;
} else {
d = (double) u.i64;
}
return d/(+2.0 * 0x7ff0000000000000) + 0.5;
}
//与this answer
类似的测试代码 -inf 0.0000000000000000
-1.797693e+308 0.0000000000000000
-3.141593e+00 0.24973844740430023
-2.718282e+00 0.24979014633262589
-1.000000e+00 0.25012212994626282
-2.225074e-308 0.49975574010747437
-4.940656e-324 0.50000000000000000
-0.000000e+00 0.50000000000000000
0.000000e+00 0.50000000000000000
4.940656e-324 0.50000000000000000
2.225074e-308 0.50024425989252563
1.000000e+00 0.74987787005373718
2.718282e+00 0.75020985366737414
3.141593e+00 0.75026155259569971
1.797693e+308 1.0000000000000000
inf 1.0000000000000000