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

爷,独闯天下 提交于 2019-12-05 19:11:18

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

Perhaps. If not, it is easy enough to form a function to assigned a sequence number to each double value.

Assuming matching FP/integer for endian & size and typical FP layout like double64, the below is valid -INF to 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;
}

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

Simply subtract the sequence numbers. +1 or -1 depending on if an open or closed range.

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

Notes:
Keep in mind that FP are logarithmically distributed overall and linear within powers of 2.
For about half of all FP, |x| < 1.0.
There are as many FP numbers 0.5 to 1.0 as between 16.0 to 32.0.
There are over twice as many double in the [-48.0 ... 48.0] versus [0.0 ... 1.0] range, primarily due to negative values.

Given a positive IEEE 754 double precision floating point number with exponent e and mantissa m, both interpreted as an integer, the distinct values (not counting denormalized values) less than it but greater than zero will be exactly m + (e - 1) * 2^52.

Which could be extracted like so

#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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!