题
我正在执行一些需要表示的数据类型转换 uint
, long
, ulong
和 decimal
作为 IEEE 754 双浮点值。我希望能够在执行转换之前检测 IEEE 754 数据类型是否不能包含该值。
一个蛮力解决方案是将 try-catch 包裹在演员表上以双重寻找 OverflowException
. 。通读某些 CLR 文档 意味着某些转换只是默默地更改值,没有任何例外。
有没有万无一失的方法来进行这项检查?我正在寻找完整性而不是易于实施。我有一种感觉,我将仔细阅读 IEEE 754 规范并仔细检查 matissa 和指数......
我应该补充一点,我是 最多 关心的是准确地表示整数,而浮点精度的损失是次要的问题(但仍然值得考虑)。
编辑: Int32 能够完全表达为 IEE-754。还有 Decimal
数据类型是问题的重要组成部分。
重要更新: 如果您提到这个问题,您还应该阅读这个问题: IEEE-754 双精度(64 位浮点)与 IEEE-754 双精度(64 位浮点)对比重温长(64 位整数)
它指出了答案中的一个缺陷,即一些非常大的值也可以由 IEEE-754 精确表示。虽然这可能意味着该值将正确往返,但出于我最初的目的(它将往返于 JavaScript),它不会。
此外,CLR System.Double 类型中似乎存在错误,因为它无法正确允许这些值往返。
解决方案
简单的解决方案可能类似于(如果x是int ):
if ((int)(double)x != x) {
// won't convert
} else {
// will convert
}
以及其他等等。
(double)x将x从int转换为double。 (int)然后再将它转换回来。所以(int)(double)x将一个int转换为一个double然后再转换回来。本质上,代码检查转换为double是可逆的(因此double可以存储int的确切值)。
其他提示
这主要取决于您正在操作的号码范围。只要您的数字在 15 位以内(对于 双倍的),对于整数,您应该保持安全。
基本上,您需要考虑的是有效位数。因此,只要您的数字小于有效数字限制,它就会保持准确;如果它变大,您将失去精度(即使这些是整数)。
因此,只要您的数字 < 2^53,您通常就很好。
IEEE 754 Double有52位用于尾数,你从/转换为整数/长,因此很容易测试。如果你的整数消耗少于52位,那么它应该可以毫无问题地转换为IEEE 754 double。
我假设(我确定在Java的情况下但不知道C#并且懒得检查)int是32位而long是64位。因此,为了确保int可以适合双倍而没有任何问题,无论是签名还是不签名。
对于ulong,你只需要高于第52位的所有位都是((aULong <!> amp; <!> amp; 0xFFF0000000000000)== 0)。
很长一段时间,你必须将其登录考虑在内。由于Long是第二补码,但IEEE754不是(只有负位),它认为将负长转换为正(* -1)并检查为正数是安全的。因此,如果长期为负数,则首先将其设为-1(对于正数不做任何事情)。然后,检查它像ulong。
希望这有帮助。