代码之家  ›  专栏  ›  技术社区  ›  markzzz

是否有一个函数来检索范围内可用的不同值的数量?

  •  3
  • markzzz  · 技术社区  · 7 年前

    我正在制作的应用程序中使用双精度浮点变量。

    我规范化了一些值范围。从(例如,我有许多范围) -48.0 48.0 0.0 1.0 ,使用此函数:

    double ToNormalizedParam(double nonNormalizedValue, double min, double max, double shape) {
        return pow((nonNormalizedValue - min) / (max - min), 1.0 / shape);
    }
    

    我想知道从一个范围映射到另一个范围的可用值和不同值之间的差异。

    C++中有现成的函数吗?我已经看过了 numeric_limits ,但我找不到任何有用的东西。

    2 回复  |  直到 7 年前
        1
  •  4
  •   chux    7 年前

    C++中有现成的函数吗?

    可能如果没有,就很容易形成一个函数,为每个函数分配一个序列号 double 价值

    假设endian的FP/integer匹配(&尺寸和典型FP布局 double64 ,以下有效 -INF INF .

    // Return a sequence number for each `double` value.
    // Numerically sequential `double` values will have successive (+1) sequence numbers.
    uint64_t double_sequence(double x) {
      uint64_t u64;
      memcpy(&u64, &x, sizeof u64);
      if (u64 & 0x8000000000000000) {
        u64 ^= 0x8000000000000000;
        return 0x8000000000000000 - u64;
      }
      return u64 + 0x8000000000000000;
    }
    

    是否有一个函数来检索范围内可用的不同值的数量?

    只需减去序列号+1或-1取决于 open or closed range .

    double_sequence(1.0)  - double_sequence(0.0)   + 1 --> 0x3ff0000000000001
    double_sequence(48.0) - double_sequence(-48.0) + 1 --> 0x8090000000000001
    

    笔记:
    请记住,FP整体呈对数分布,在2的幂内呈线性。
    大约一半的FP, |x| < 1.0 .
    在16.0到32.0之间,有多达0.5到1.0的浮点数。
    有两倍多 [-48.0 ... 48.0] [0.0 ... 1.0] 范围,主要是由于负值。

        2
  •  1
  •   Passer By    7 年前

    给定正IEEE 754双精度浮点数和指数 e 和尾数 m ,两者都被解释为整数,小于但大于零的不同值(不计算非规范化值)将精确为 m + (e - 1) * 2^52 .

    可以这样提取

    #include<iostream>
    #include<tuple>
    #include<cstdint>
    #include<cstring>
    
    using std::uint64_t;
    
    std::tuple<uint64_t, uint64_t, uint64_t> explode(double d)
    {
        static_assert(sizeof(double) == 8);
        uint64_t u;
        std::memcpy(&u, &d, sizeof(d));
        return { (u & 0x8000000000000000) >> 63,
                 (u & 0x7FF0000000000000) >> 52,
                  u & 0x000FFFFFFFFFFFFF };
    }
    
    uint64_t distinct(double d)
    {
        auto [_, e, m] = explode(d);
        return m + ((e - 1) << 52);
    }
    
    int main()
    {
        std::cout << "[-48, 48]: " << 2 * distinct(48) << "\n[0, 1]: " << distinct(1) << '\n';
    }
    

    Live