如何以最大精度将5个浮点数均匀编码为4个浮点数

问题描述 投票:0回答:1

我最初会问这个,但我发现我自己的解决方案效果很好,所以我会在这里发布这个以供参考。

简而言之,我的情况是,我有4个可用的通道,已经使用过了,我想在另一个第5个值中吝啬,平均使用每个通道(因为这些值是相关的),同时保持尽可能高的精度。

请参阅我的解决方案。如果你找到更好/更快的或者只是找到优化,我会很感激你的回答!

floating-point shader precision
1个回答
0
投票

所以我开始想要将第五个浮子分成四个相等的部分(如同,需要相同的精度)并将它们混合到其他四个值中,这样第五个浮点数的总精度将是相同的作为其他4个花车。

所以我设置了这个等式,结果证明是非常有帮助的(如果你有不同的要求,请从这里开始!):

y * py + x * px * py <= 256^3

256 ^ 3是整数仍可安全区分的最大浮点值,

x = 4个向量浮点数的最大值,

y =第5个浮点数的最大值,

px =向量浮点数的总精度,

py =第5个浮子的4个部分中的每一个的精度,

最后px = py ^ 4来设置条件,即所有四个部分组合以获得第五个浮点数应该具有与所有其他浮点数相同的精度。在这里,您应该能够添加一个因子,使第5个浮点数或其他4个更高或更低的精度,由您决定。

这解决了:

y * py + x * py^4 * py <= 256^3

在我的情况下,y和x都是1,所以:

py + py^5 <= 256^3

把它放在Wolfram Alpha中或计算大致如下:

py = 256^(3/5)

我们得到:

py = 27.86 ~= 27
px = 27^4

测试,你会看到:

27 + 27^5 = 14348934 < 256^3 = 16777216

因此,如果所有5个浮点数的范围都是0-1,并且您希望给所有5个浮点数提供相同的精度,那么27就是神奇的精确数字(经过验证,见下文)。所有涉及浮标的实际精度是27 ^ 4 = 531441中的1个部分,这是充足的。

获得精度数后,请使用以下代码,用C#编写Unity(需要调整x / y!= 1或px!= py ^ 4):

public Vector4 Encode(Vector4 x, float y)
{
    float p = 27; // So that p^5+p < 256^3; approx: 256^(3/5) = 27.85 => 27; Actual precision is 1/(27^4) = 1/531441
    float p0 = 1, p1 = p, p2 = p * p, p3 = p * p * p, p4 = p * p * p * p;

    // Split in 4 y-floats
    float yC = y * (p4 - 1);
    float yC1 = Mathf.Floor(yC % p4 / p3);
    float yC2 = Mathf.Floor(yC % p3 / p2);
    float yC3 = Mathf.Floor(yC % p2 / p1);
    float yC4 = Mathf.Floor(yC % p1 / p0);

    // Test by combining each z-float again
    //float yTest = (yC1 * p3 + yC2 * p2 + yC3 * p1 + yC4 * p0) / (p4 - 1);

    // Encode each y-float into x as xC
    Vector4 xC = new Vector4(
            Mathf.Floor(x.x * p4) * p1 + yC1,
            Mathf.Floor(x.y * p4) * p1 + yC2,
            Mathf.Floor(x.z * p4) * p1 + yC3,
            Mathf.Floor(x.w * p4) * p1 + yC4);

    return xC;
}

public Vector4 Decode(Vector4 xC, out float yDC)
{
    float p = 27; // So that p^5+p < 256^3; approx: 256^(3/5) = 27.85 => 27
    float p0 = 1, p1 = p, p2 = p * p, p3 = p * p * p, p4 = p * p * p * p;

    // Decode xC to get each y-float
    float yDC1 = xC.x % p1;
    float yDC2 = xC.y % p1;
    float yDC3 = xC.z % p1;
    float yDC4 = xC.w % p1;

    // Combine y-floats to get decoded y as yDC
    yDC = (yDC1 * p3 + yDC2 * p2 + yDC3 * p1 + yDC4 * p0) / (p4 - 1);

    // Get original x from xC as xDC
    Vector4 xDC = new Vector4(
            Mathf.Floor(xC.x / p1) / p4,
            Mathf.Floor(xC.y / p1) / p4,
            Mathf.Floor(xC.z / p1) / p4,
            Mathf.Floor(xC.w / p1) / p4);

    return xDC;
}

注意:由于不明显,代码中的整个加/减1允许对所有相关浮点中的值1和0进行正确编码和解码。

我得到以下错误结果,显示精度确实是1/27 ^ 4 = 1.88168E-06:

X Vector: Avg9.200859E-07 | Max1.881272E-06  Y Float : Avg9.223418E-07 | Max1.881272E-06

要证明27是最佳位置,这里是26的值:

X Vector: Avg1.072274E-06 | Max2.190471E-06  Y Float : Avg1.07382E-06  | Max2.190471E-06

最后是28(导致某些值接近1的溢出):

X Vector: Avg7.914192E-07 | Max1.66893E-06  Y Float : Avg0.001480901 | Max0.9987262
© www.soinside.com 2019 - 2024. All rights reserved.