C++ 带浮点数的2D点Morton索引

C++ 带浮点数的2D点Morton索引,c++,algorithm,z-order-curve,C++,Algorithm,Z Order Curve,我有一个2D点,看起来像这样: class Point { float m_x, m_y; public: int mortonIndex() { // what would go here? } }; 我知道如何处理整数,但我需要使用浮点数。我还希望避免任何特定网格大小的缩放 维基百科的相关页面: 有两种方法来看待这一点: “float”是256位的数字,(或者类似地,“double”是2100位的数字,在这里实现[1])。 “fl

我有一个2D点,看起来像这样:

class Point
{
    float m_x, m_y;

public:

    int mortonIndex()
    {
        // what would go here?
    }
};
我知道如何处理整数,但我需要使用浮点数。我还希望避免任何特定网格大小的缩放

维基百科的相关页面:
有两种方法来看待这一点:

  • “float”是256位的数字,(或者类似地,“double”是2100位的数字,在这里实现[1])。
  • “float”是一个奇怪的32位整数。
我将使用后者,因为它更容易实现

这种方法利用了IEEE
float
s最初设计为与旧的纯整数数据库引擎兼容的事实,允许它们将浮点数视为1s补码整数

更准确地说,在1s补码意义上,浮点值的顺序尊重相同宽度的整数的顺序(事实上,直接向双关浮点加1将得到具有更大绝对大小的相邻值**)

类点
{
浮动m_x,m_y;
//当使用浮点模型时,此断言不正确
//不符合IEEE标准,浮点不是32位,或两者兼而有之。
//
//这样的东西很难找到,所以我们只能假设
//大部分是健全的硬件。
//
静态断言(
(sizeof(int)=sizeof(float))&&
(sizeof(int)*字符位==32)&&
(sizeof(long-long)*字符位==64),
“我们需要32位整数和浮点数,以及64位长的长整数!”
);
公众:
//所以我们不会丢失任何信息,我们需要2倍的宽度。
//毕竟,我们把两个32位数字塞进了一个值中。
//这里的丢失意味着需要实现一个容器
//装箱策略。
//
//显然,更高的维度需要一个数组。
//
//另外,我们不打算修改这个点,所以让它成为一个常量例程。
//
长mortonIndex()常数
{
//将x和y坐标双关为整数:只需重新解释位。
//
auto ix=重新解释铸型(此->m_x);
auto iy=重新解释投射(此->m_y);
//由于我们假设2s补码算法(目前99.99%的硬件),
//我们需要将这些原始整数双关浮点转换为
//它们对应的整数“指数”。
//把他们的符号涂在上面,让他们在下面玩。
//
const auto ixs=静态_cast(ix)>>31;
const auto iys=静态施法(iy)>>31;
//这是快速绝对值和偏差的组合。
//
//我们需要调整这些值,使-FLT_MAX接近于0。
//
ix=((ix&0x7FFFFFL)^ixs)-ixs)+0x7FFFFFL;
iy=((iy&0x7FFFFFL)^iys)-iys)+0x7FFFFFL;
//现在我们有-FLT_MAX接近0,FLT_MAX接近UINT_MAX,
//其他一切都在中间。
//
//为了简化这个过程,我们将x和y作为64位整数。
//
长xx=ix;
long-long yy=iy;
//像往常一样扩张和合并。。。

xx=(xx |)(xx什么是莫顿指数?是的,我可以用谷歌搜索它,但也许你可以把它放在你的问题中,这样我就不用问了。它们也被称为“Z指数”或“勒贝格曲线上的点”.对我来说似乎是个直截了当的问题。如果你不知道莫顿指数是什么,你不必为它烦恼。这些神奇的数字是什么?我是说“0x0000FFFF0000FFFFL”以此类推……再加上同一语句中的移位,它们掩盖了我们不想在那一步放大的值的一半。如果你用手做这个,比如说所有的1,你会注意到这会“分散”位。上的例子有助于理解神奇的数字。
class Point
{
    float m_x, m_y;

    // This assert is not correct when the floating point model
    // is not IEEE-compliant, float is not 32-bit, or both.
    //
    // Such things are hard to find, so we'll just assume
    // mostly-sane hardware.
    //
    static_assert(
        (sizeof(int) == sizeof(float)) &&
        (sizeof(int)*CHAR_BIT == 32) &&
        (sizeof(long long)*CHAR_BIT == 64),
        "We need 32-bit ints and floats, and 64-bit long longs!"
        );

public:

    // So we don't lose any information, we need 2x the width.
    // After all, we're cramming two 32-bit numbers into a single value.
    // Lossiness here would mean a container would need to implement
    // a binning strategy.
    //
    // Higher dimensions would require an array, obviously.
    //
    // Also, we're not going to modify the point, so make this a const routine.
    //
    long long mortonIndex() const
    {
        // Pun the x and y coordinates as integers: Just re-interpret the bits.
        //
        auto ix = reinterpret_cast<const unsigned &>(this->m_x);
        auto iy = reinterpret_cast<const unsigned &>(this->m_y);

        // Since we're assuming 2s complement arithmetic (99.99% of hardware today),
        // we'll need to convert these raw integer-punned floats into
        // their corresponding integer "indices".

        // Smear their sign bits into these for twiddling below.
        //
        const auto ixs = static_cast<int>(ix) >> 31;
        const auto iys = static_cast<int>(iy) >> 31;

        // This is a combination of a fast absolute value and a bias.
        //
        // We need to adjust the values so -FLT_MAX is close to 0.
        //
        ix = (((ix & 0x7FFFFFFFL) ^ ixs) - ixs) + 0x7FFFFFFFL;
        iy = (((iy & 0x7FFFFFFFL) ^ iys) - iys) + 0x7FFFFFFFL;

        // Now we have -FLT_MAX close to 0, and FLT_MAX close to UINT_MAX,
        // with everything else in-between.
        //
        // To make this easy, we'll work with x and y as 64-bit integers.
        //
        long long xx = ix;
        long long yy = iy;

        // Dilate and combine as usual...

        xx = (xx | (xx << 16)) & 0x0000ffff0000ffffLL;
        yy = (yy | (yy << 16)) & 0x0000ffff0000ffffLL;

        xx = (xx | (xx <<  8)) & 0x00ff00ff00ff00ffLL;
        yy = (yy | (yy <<  8)) & 0x00ff00ff00ff00ffLL;

        xx = (xx | (xx <<  4)) & 0x0f0f0f0f0f0f0f0fLL;
        yy = (yy | (yy <<  4)) & 0x0f0f0f0f0f0f0f0fLL;

        xx = (xx | (xx <<  2)) & 0x3333333333333333LL;
        yy = (yy | (yy <<  2)) & 0x3333333333333333LL;

        xx = (xx | (xx <<  1)) & 0x5555555555555555LL;
        yy = (yy | (yy <<  1)) & 0x5555555555555555LL;

        return xx | (yy << 1);
    }
};