将范围内的任何值(-inf ... + inf)归一化为(0 ... 1)。可能吗?

时间:2017-02-09 15:15:02

标签: math range normalize

如果我们具有max..min值的具体范围,很容易将其标准化为0..1浮点值,但是如果我们没有具体限制?是否可以构建通用函数以使输出在0和1之间?在我看来,我认为这是不可能的,但我不是数学专家。

我正在寻找JavaScript或PHP的实现,但是C / C ++ / Python / Delphi上的任何代码都可以提供示例(如果有的话)

3 个答案:

答案 0 :(得分:6)

有很多方法可以做到这一点。我将省略映射-inf+inf,这可以使用条件语句完成。

  1. exp(x) / (1 + exp(x))或等效1 / (1 + exp(-x)),其中exp是指数函数。这是一项后勤功能。
  2. atan(x) / pi + 1 / 2
  3. (tanh(x) + 1) / 2
  4. (1 + x / sqrt(1 + x*x)) / 2
  5. (1 + x / (1 + abs(x)) / 2
  6. (erf(x) + 1) / 2
  7. 您可能已经注意到,其中大多数都采用映射到(-1,1)并将其更改为(0,1)。前者通常更容易。以下是这些功能的图表:

    在我的Python 3.5.2中,最快的是(1 + x / (1 + abs(x)) * 0.5

    enter image description here

答案 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

1000 samples

答案 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