Как проверить, изменится ли числовое значение?

StackOverflow https://stackoverflow.com/questions/1601646

  •  05-07-2019
  •  | 
  •  

Вопрос

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

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

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

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

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

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

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

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

Это было полезно?

Решение

Простое решение может быть примерно таким (, если 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).

Другие советы

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

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top