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

Is there a function to retrieve the number of available distinct values within a range?

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

我标准化了一些值范围。从(例如;我有很多范围)-48.048.00.01.0,使用这个简单的函数:

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

我想知道从一个范围映射到另一个范围的可用值和不同值的区别。

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

给定一个带指数 e 和尾数 m 的正 IEEE 754 双精度浮点数,两者都被解释为整数,不同的值(不包括非规范化值)小于但大于比零正好是 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

Is there a ready-to-go function in C++?

也许吧。如果没有,很容易形成一个函数来为每个 double 值分配一个序列号。

假设字节序和大小匹配 FP/integer 和像 double64 这样的典型 FP 布局,下面是有效的 -INFINF

// 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;
}

Is there a function to retrieve the number of available distinct values within a range?

只需减去序号即可。 +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.
FP 数字 0.5 到 1.0 与 16.0 到 32.0 之间的一样多。
[-48.0 ... 48.0] 范围内的 double[0.0 ... 1.0] 范围内的两倍多,这主要是由于负值。