如何测试数字转换是否会改变值?

时间:2009-10-21 15:28:56

标签: c# clr ieee-754

我正在执行一些数据类型转换,我需要将uintlongulongdecimal表示为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类型中似乎也存在一个错误,因为它没有正确地允许这些值进行往返。

3 个答案:

答案 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。

希望这有帮助。