Исключение с плавающей запятой для типа double -> unsigned __int64 в C++ Builder 10.1
В C++ Builder 10.1 Berlin возникает проблема с определенными типами типов с двойным и без знака __int64 в Берлине, вызывающими исключение недопустимой операции с плавающей запятой ($C0000090).
Мое приложение позволяет вводить данные пользователем, поэтому мне нужно иметь возможность обрабатывать любые значения, но для простоты, давайте использовать следующий пример:
double dValue = 9223372036854775807.0;
unsigned __int64 uhValue = (unsigned __int64) dValue;
Хотя я могу обработать это исключение при попытке / перехвате, это, похоже, повредит стек регистров FPU, и последующие операции с плавающей запятой сгенерируют исключение проверки стека с плавающей запятой.
В следующем отчете о проблеме описана похожая проблема, и на ней есть потенциальное решение: http://qc.embarcadero.com/wc/qcmain.aspx/qcmain.aspx?d=119745
Я хотел бы предотвратить первоначальное исключение с плавающей запятой, если это вообще возможно. Помимо потери точности, значение, хранящееся в double, находится в допустимом диапазоне без знака __int64, поэтому у меня возникают проблемы с пониманием того, что вызывает исключение.
Есть ли что-то, что я мог бы сделать по-другому, когда дело доходит до обработки / преобразования типов или обработки исключений?
Как примечание, фрагмент кода выше отлично работает в Visual Studio и устанавливает для uhValue значение 9223372036854775808.
Спасибо!
1 ответ
Я использую только старый BDS2006, поэтому не могу проверить ваши условия. Но вы можете загрузить себя... как-то так:
Чистая 64-битная версия будет выглядеть так:
#pragma warn -8056
unsigned __int64 load(double x) // MSb sign(1),exp(11),1.0+mant(52) LSb
{
int exp;
unsigned __int64 y, *q = ((unsigned __int64*)(&x));
exp = (*q >> 52) & 0x7FF; // extract exponent
if (exp == 0x7FF)
return 0; // here handle +/- inf value
else
{ // extract mantissa and debiass exponent
if (exp == 0x00) // denormalized form 0.000001
{
exp = -1024;
y = *q & 0x000FFFFFFFFFFFFF;
}
else
{ // normalized form 1.000001
exp -= 1023;
y = *q & 0x000FFFFFFFFFFFFF;
y |= 0x0010000000000000;
}
}
// update your 64bit value with exponent shift and sign (this part is untested)
exp -= 52;
if (exp > 0)
y <<= +exp;
if (exp < 0)
y >>= -exp;
if (*q >= 0x8000000000000000)
y = -y; // handle sign
return y;
}
#pragma warn .8056
Надеюсь, я не сделал глупости, так как не могу это проверить (мой компилятор не поддерживает 64-битную арифметику) код был взят из моего класса arbnum double
загрузчик и изменения в соответствии с вашими потребностями.
Кстати, я не совсем убежден, что актеры - это проблема, с которой я боролся с подобными проблемами в своих проектах раньше. Я нашел две основные причины, по которым они производились самостоятельно:
используя OpenGL, где пары
glBegin()/glEnd()
не был должным образом сбалансирован.Отсутствует
glEnd()
выкидывал исключения стека FPU все время в несвязанном коде к этому...BCB6 унаследовал ошибку движка и компилятора Borland C++.
Я не использую BCB6 (я на BDS2006), но вы, ребята, подтвердили, что он также присутствует (BCB5 был в порядке) и, возможно, также в более новых версиях Borland. Просто конструктор по умолчанию, сгенерированный компилятором, содержит ошибки, приводящие к хаосу в компиляторе и движке C++. В сочетании с ошибкой диспетчера памяти (двойное удаление указателя не выдает исключение, а делает недействительным диспетчер памяти), вы можете в любое время лишить законной силы указатели, не зная, что они перезаписывают даже части кода в памяти... не говоря уже о случайных исключениях любого вида (наиболее вероятных) является нарушением прав доступа), но я получил то же дерьмо FPU, что и вы, для некоторых проектов, прежде чем я получил в конце этой вещи (кстати, вы можете использовать один
fninit
Инструкция по восстановлению ФПУ время от времени в крайнем случае).Для получения дополнительной информации и как ее решить см.: