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