c# - 将 float 转换为 UInt32 - 哪个表达式更精确

标签 c# floating-point floating-point-precision numerical-stability

我有一个数字 float x,它应该在 <0,1> 范围内,但它经过了几次数值运算 - 结果可能略微超出 <0,1>。

我需要使用 UInt32 的整个范围将此结果转换为 uint y。当然,我需要将 x 限制在 <0,1> 范围内并对其进行缩放。

但是哪种操作顺序更好呢?

y = (uint)round(min(max(x, 0.0F), 1.0F) * UInt32.MaxValue)

y = (uint)round(min(max(x * UInt32.MaxValue, 0.0F), UInt32.MaxValue)

换句话说,是先缩放,再钳制还是先钳制再缩放更好?我对 IEEE 浮点表示不是很了解,但我相信上述表达式的计算顺序有所不同。

最佳答案

因为从 [0.0f .. 1.0f] 到 [0 .. UInt32.MaxValue] 的乘法本身可以是近似的,所以最明显具有您想要的属性的操作顺序是乘法,然后是钳位,然后圆。

要限制的最大值是紧接在 232 以下的 float ,即 4294967040.0f。尽管此数字比 UInt32.MaxValue 低几个单位,但允许任何更大的值将意味着溢出到 UInt32 的转换。

以下任何一行都应该有效:

y = (uint)round(min(max(x * 4294967040.0F, 0.0F), 4294967040.0F))

在第一个版本中,您可以选择乘以 UInt32.MaxValue。选择是在总体结果略大一些(因此将接近 1.0f 但低于 1.0f 的值舍入到 4294967040)之间,或者只向 4294967040 发送 1.0f 及以上的值。


您也可以限制在 [0.0f .. 1.0f] 如果您之后没有乘以太大的数字,这样就没有使值大于最大 float 的风险可以转换:

y = (uint)round(min(max(x, 0.0F), 1.0F) * 4294967040.0F)

关于制作达到 UInt32.MaxValue 的转换的以下评论建议:

if (x <= 0.0f) y = 0
else if (x < 0.5f) y = (uint) round (x * 4294967296.0F)
else if (x >= 1.0f) y = UInt32.MaxValue
else y = UInt32.MaxValue - (uint) round ((1.0f - x) * 4294967296.0F)

这个计算被认为是从 xy 的函数正在增加(包括大约 0.5f)并且它上升到 UInt32.MaxValue .您可以根据您认为最可能的值分布对测试重新排序。特别是,假设很少有值实际低于 0.0f 或高于 1.0f,您可以先与 0.5f 进行比较,然后仅与相关的界限进行比较:

if (x < 0.5f)
{
  if (x <= 0.0f) y = ...
  else y = ...
}
else
{
  if (x >= 1.0f) y = ...
  else y = ...
}

关于c# - 将 float 转换为 UInt32 - 哪个表达式更精确,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24360347/

相关文章:

c# - 从 C# 连接到 .accdb。 "Unrecognized database format"错误

c# - 从 blobBaseClient.DownloadToAsync 获取 FullContent

c# - 卷影复制,以及从任意文件夹加载的混合 C# 和 C++ DLL

javascript - 如何将数字 2.00 作为一个完整的字符串输出?

c - 为什么这个浮点循环在 1,000,000 处终止?

sql - 在不损失精度的情况下将 SQL Geography Lat/Long 转换为 VARCHAR

java - 处理浮点精度问题(测试与SAT的碰撞)

c# - 为什么长时间运行不返回任何数据的 SQL 命令会产生数百 MB 的网络流量

java - 将浮点型转换为带逗号的字符串,不进行四舍五入或小数点更改

javascript - 一般 float 学查询