Как проверить, изменится ли числовое значение? - PullRequest
3 голосов
/ 21 октября 2009

Я выполняю некоторые преобразования типов данных, где мне нужно представить uint, long, ulong и decimal как двойные значения с плавающей запятой IEEE 754. Я хочу быть в состоянии определить, может ли тип данных IEEE 754 не содержать значение, прежде чем выполнить преобразование.

Решением для грубой силы было бы обернуть пробную ловушку вокруг броска, чтобы удвоить поиск OverflowException. Прочтение некоторых документов CLR подразумевает, что некоторые преобразования просто без каких-либо исключений изменяют значение.

Есть ли какой-нибудь надежный способ сделать эту проверку? Я ищу полноты над простотой реализации. У меня такое чувство, что я буду внимательно читать спецификацию IEEE 754 и тщательно проверять матиссу и экспоненту ...

Я должен добавить, что я большинство обеспокоен точным представлением целых чисел, и что потеря точности с плавающей запятой имеет второстепенное значение (но все же стоит рассмотреть).

РЕДАКТИРОВАТЬ: Int32 может быть полностью выражен как IEE-754. Кроме того, тип данных Decimal является очень важной частью вопроса.

Важное обновление: Если вы имеете в виду этот вопрос, вам также следует прочитать этот вопрос: IEEE-754 Double (64-разрядная с плавающей запятой) против Long (64-разрядное целое) Revisited

Он отмечает недостаток в ответе, когда некоторые очень большие значения также могут быть точно представлены IEEE-754. Хотя это может означать, что значение будет правильно в обоих направлениях, для моей первоначальной цели (будет ли это в обоих направлениях в JavaScript) оно не будет.

Также, похоже, есть ошибка в типе CLRs System.Double, потому что он не позволяет правильно использовать эти значения в обратном направлении.

Ответы [ 3 ]

9 голосов
/ 21 октября 2009

Простое решение может быть что-то вроде (, если x является целым ):

if ((int)(double)x != x) { 
  // won't convert
} else {
  // will convert
}

и т. Д. Долго и т. Д.

(double) x преобразует x из целого числа в double. Затем (int) снова преобразует его. Таким образом (int) (double) x преобразует форму int в double, а затем обратно. По сути, код проверяет, что преобразование в double является обратимым (и, следовательно, что double может хранить точное значение типа int).

1 голос
/ 21 октября 2009

IEEE 754 Double имеет 52 бита для мантиссы, и вы конвертируете из / в целое / длинное , так что его довольно легко протестировать. Если ваше целое число потребляет менее 52 бит, то оно должно быть без проблем преобразовано в двойной стандарт IEEE 754.

Я предполагаю (я точно знаю, что в случае с Java, но не в C #, и лениво проверять), что int равен 32 битам, а long - 64 битам. Так что наверняка int может поместиться в double без каких-либо проблем, как sign, так и unsign.

Для ulong вам просто нужно, чтобы все биты выше 52-го были одинаковыми ((aULong && 0xFFF0000000000000) == 0).

В течение долгого времени вы должны довести его знак до рассмотрения. Поскольку Long является вторым дополнением, а IEEE754 - нет (просто имеет отрицательный бит), он может просто преобразовать отрицательный длинный в положительный (* -1) и проверить как положительный. Так что, если long отрицательный, время его сначала -1 (ничего не делать для положительного). Затем проверьте это как ulong.

Надеюсь, это поможет.

1 голос
/ 21 октября 2009

Это в основном зависит от диапазона номеров, с которым вы работаете. Пока вы находитесь в пределах 15 цифр (для double ), вы должны быть в безопасности для целых чисел.

По сути, вам нужно учитывать количество значащих цифр. Таким образом, до тех пор, пока ваш номер меньше значащего лимита цифр, он останется точным; если он станет больше, вы потеряете точность (даже если это целые числа).

Так что, пока ваш номер <2 ^ 53, вы обычно хороши. </p>

...