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



我最初打算问这个问题,但事实证明我自己的解决方案效果很好,所以我在这里发布这个以供参考。

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

请参阅我的解决方案答案。如果您找到更好/更快的一个或只是找到要做的优化,我将不胜感激您的回答!

因此,我开始的想法是将第 5 个浮点数分成四个相等的部分(如,需要相同的精度(,并将它们混合到其他四个值中,以便第 5 个浮点数的总精度与其他 4 个浮点数相同

所以我设置了这个方程,结果证明它有很大的帮助(如果你和我有不同的要求,请从这里开始!

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

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

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

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

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

py = 第 5 个浮点数的 4 个部分中每个部分的精度,

最后 px = py^4 设置条件,即所有四个部分组合在一起以获得第 5 个浮点数应具有与所有其他浮点数相同的精度。在这里,您应该能够添加一个因子,使第 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# for 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

最新更新