带有浮点数的二维点的莫顿指数[关闭]

Posted

技术标签:

【中文标题】带有浮点数的二维点的莫顿指数[关闭]【英文标题】:Morton index from 2D point with floats [closed] 【发布时间】:2015-01-07 11:49:35 【问题描述】:

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

class Point

    float m_x, m_y;

public:

    int mortonIndex()
    
        // what would go here?
    
;

我知道如何处理整数,但我需要使用浮点数。我还想避免针对任何特定的网格大小进行缩放。

***相关页面:

Morton index, or Z order curve

【问题讨论】:

什么是莫顿指数?是的,我可以用谷歌搜索它,但也许你可以把它放在你的问题中,这样我就不必这样做了。 它们也被称为“Z 指数”或“勒贝格曲线上的点”。 对我来说似乎是一个直截了当的问题。如果您不知道什么是 Morton 指数,则无需费心。 【参考方案1】:

有两种查看方式:

一个 `float` 是一个 256 位的数字,(或者类似地,一个 `double` 作为一个 2100 位的数字,在 [here][1] 中实现)。 `float` 是一个奇怪的 32 位整数。

我会使用后者,因为它更容易实现。

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

更准确地说,在 1s 补码意义上,浮点值的排序尊重相同宽度的整数的排序(实际上,直接将 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);
    
;

请注意,生成曲线的顶点与 2D 浮点空间中的位置具有相同的分布。

如果您打算将其与磁盘结构一起使用,这可能会出现问题,因为在坐标轴或原点附近聚集可能会导致范围查询跨越它们附近的大量框。否则,IMO,它是生成统一索引(并且它没有分支!)的合理性能替代方案。

**对于无穷大和 NaN 需要特殊处理,但你明白了。

【讨论】:

幻数有什么用?我的意思是“0x0000ffff0000ffffLL”等等...... 结合同一个语句中的移位,它们掩盖了我们不想在该步骤膨胀的一半值。如果您手动执行此操作以获得一个值,例如全 1,您会注意到这会将位“展开”。 asgerhoedt.dk/?p=276 的例子有助于理解神奇的数字。

以上是关于带有浮点数的二维点的莫顿指数[关闭]的主要内容,如果未能解决你的问题,请参考以下文章

什么是浮点数格式?

ieee754单精度浮点数 表示方法

返回浮点数的指数值

Javascript将浮点数转换为指数[重复]

关于IEEE754标准浮点数阶码的移码

浮点数