将两个浮点值存储在一个浮点变量中
Posted
技术标签:
【中文标题】将两个浮点值存储在一个浮点变量中【英文标题】:Storing two float values in a single float variable 【发布时间】:2013-07-14 10:59:13 【问题描述】:我想将两个浮点值存储在一个 32 位浮点变量中。编码将在 C# 中进行,而解码将在 HLSL 着色器中完成。
到目前为止,我发现的最佳解决方案是将小数点的偏移量硬连接到编码值中,并将它们存储为“载体”浮点数的整数和小数:
123.456 -> 12.3 and 45.6
它不能处理负值,但没关系。
但是我想知道是否有更好的方法来做到这一点。
编辑:关于任务的更多细节:
我正在使用 Unity 中的固定数据结构,其中顶点数据存储为浮点数。 (Float2 用于 UV,float3 用于法线,等等。)显然没有办法正确添加额外的数据,所以我必须在这些限制内工作,这就是为什么我认为这一切都归结为更普遍的编码数据问题.例如,我可以牺牲辅助 UV 数据来传输 2x2 额外的数据通道。
目标是着色器模型 3.0,但我不介意解码在 SM2.0 上是否也能正常工作。
只要“合理”,数据丢失就可以了。预期值范围是 0..64,但我认为 0..1 也可以,因为重新映射到着色器内的任何范围都很便宜。重要的是保持尽可能高的精度。负值并不重要。
【问题讨论】:
@ZoltanE:你知道你要编码的变量的范围吗? @ZoltanE:还有,你的目标是什么着色器模型和 DirectX 版本?您能否详细说明为什么要这样编码?最后:考虑在gamedev 网站上提问,您可能会得到更好的答案。 也许***.com/questions/4811219/pack-four-bytes-in-a-float这个问题对你有帮助。 【参考方案1】:按照 Gnietschow 的建议,我调整了 YellPika 的算法。 (它是 Unity 3d 的 C#。)
float Pack(Vector2 input, int precision)
Vector2 output = input;
output.x = Mathf.Floor(output.x * (precision - 1));
output.y = Mathf.Floor(output.y * (precision - 1));
return (output.x * precision) + output.y;
Vector2 Unpack(float input, int precision)
Vector2 output = Vector2.zero;
output.y = input % precision;
output.x = Mathf.Floor(input / precision);
return output / (precision - 1);
快速而肮脏的测试产生了以下统计数据(0..1 范围内的 100 万个随机值对):
Precision: 2048 | Avg error: 0.00024424 | Max error: 0.00048852
Precision: 4096 | Avg error: 0.00012208 | Max error: 0.00024417
Precision: 8192 | Avg error: 0.00011035 | Max error: 0.99999940
4096 的精度似乎是最佳选择。请注意,这些测试中的打包和解包都在 CPU 上运行,因此如果 GPU 以浮点精度偷工减料,结果可能会更糟。
无论如何,我不知道这是否是最好的算法,但对于我的情况来说似乎已经足够了。
【讨论】:
您介意解释一下为什么input % precision
部分有效吗?您正在对浮点数和整数进行模数,但模数仅在整数上定义。
定义不限于整数:“模运算求一个数除以另一个数的余数”。问“当我将 7.7 除以 3.3 时余数是多少?”是有道理的?
注意:如果input.y
超过1
,则会中断。在那种情况下,+ output.y
只是增加了precision
的值的另一个增量——那么input % precision
只能解压input.y
的小数部分,而它的整数部分(除以precision
)被添加到@ 987654332@.
问题:如果像这样将 4 个值打包成两个浮点数,是否可以对这两个浮点数进行插值,然后将插值解包得到源值的近似插值?以上是关于将两个浮点值存储在一个浮点变量中的主要内容,如果未能解决你的问题,请参考以下文章
如何在NHibernate Criteria Query中截断浮点值?