将golang float32转换为半精度float(GLSL float16)作为uint16

时间:2020-09-17 14:24:04

标签: go half-precision-float

我需要将一些数据从Go传递到'300 es'着色器。数据由打包到uint32中的两个uint16组成。每个uint16代表一个半精度浮点数(float16)。我找到了一些看起来可以完成此工作的PD Java代码,但是我在移植最后一个语句时感到很挣扎,该语句使用了几个零扩展的右移(我认为其他的移位都很好,即非负数)。因为Go在扩展方面有点聪明,所以端口的解决方案使我望而却步。我确实认为也许第一个可以更改为左移,因为它似乎只是要定位一点以进行加法?但是最后的转变让我全神贯注:)

btw我希望我得到正确的括弧,因为Go和Java之间关于'-'和'>>'...的运算符优先级似乎有所不同。

接下来我需要走另一条路,但是如果没有右移,希望这会更容易...著名的最后一句话!

Java代码:

https://stackoverflow.com/a/6162687/345165

var mySelectedPerson = cbPeople.SelectedItem;

var name = mySelectedPerson.ToString(); // "Frank Wright" 

我的部分端口:

// returns all higher 16 bits as 0 for all results
public static int fromFloat( float fval )
{
    int fbits = Float.floatToIntBits( fval );
    int sign = fbits >>> 16 & 0x8000;          // sign only
    int val = ( fbits & 0x7fffffff ) + 0x1000; // rounded value

    if( val >= 0x47800000 )               // might be or become NaN/Inf
    {                                     // avoid Inf due to rounding
        if( ( fbits & 0x7fffffff ) >= 0x47800000 )
        {                                 // is or must become NaN/Inf
            if( val < 0x7f800000 )        // was value but too large
                return sign | 0x7c00;     // make it +/-Inf
            return sign | 0x7c00 |        // remains +/-Inf or NaN
                ( fbits & 0x007fffff ) >>> 13; // keep NaN (and Inf) bits
        }
        return sign | 0x7bff;             // unrounded not quite Inf
    }
    if( val >= 0x38800000 )               // remains normalized value
        return sign | val - 0x38000000 >>> 13; // exp - 127 + 15
    if( val < 0x33000000 )                // too small for subnormal
        return sign;                      // becomes +/-0
    val = ( fbits & 0x7fffffff ) >>> 23;  // tmp exp for subnormal calc
    return sign | ( ( fbits & 0x7fffff | 0x800000 ) // add subnormal bit
         + ( 0x800000 >>> val - 102 )     // round depending on cut off
      >>> 126 - val );   // div by 2^(1-(exp-127+15)) and >> 13 | exp=0
}

我发现了看起来更高效的代码,没有分支,但是了解我的生锈(不是语言)技能之外的一些技巧;)可以移植它。

https://stackoverflow.com/a/5587983

欢呼

[编辑]该代码似乎可以使用我当前使用的值(由于我没有调试着色器的经验,因此很难精确说明)。所以我想我的问题是关于端口的正确性,尤其是最后两个班次。

[Edit2]看来,我已经在一处弄错了优先顺序,并修复了上面的示例。

已更改:

func float32toUint16(f float32) uint16 {
    fbits := math.Float32bits(f)
    sign := uint16((fbits >> 16) & 0x00008000)
    rv := (fbits & 0x7fffffff) + 0x1000

    if rv >= 0x47800000 {
        if (fbits & 0x7fffffff) >= 0x47800000 {
            if rv < 0x7f800000 {
                return sign | 0x7c00
            }
            return sign | 0x7c00 | uint16((fbits&0x007fffff)>>13)
        }
        return sign | 0x7bff
    }
    if rv >= 0x38800000 {
        return sign | uint16((rv-0x38000000)>>13)
    }
    if rv < 0x33000000 {
        return sign
    }
    rv = (fbits & 0x7fffffff) >> 23
    return sign | uint16(((fbits&0x7fffff)|0x800000)+(0x800000>>(rv-102))>>(126-rv)) //these two shifts are my problem
}

func pack16(f1 float32, f2 float32) uint32 {
    ui161 := float32toUint16(f1)
    ui162 := float32toUint16(f2)
    return ((uint32(ui161) << 16) | uint32(ui162))
}

收件人:

    return sign | uint16(rv-(0x38000000>>13))

0 个答案:

没有答案
相关问题