Как проверить, изменится ли числовое значение?
Вопрос
Я выполняю некоторые преобразования типов данных, в которых мне нужно представить 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.
Надеюсь, это поможет.