У меня есть программный проект, в котором я иногда получаю странные результаты от небольших, простых операций с плавающей запятой. Я предполагаю, что что-то упустил, и хотел бы дать несколько советов о том, как отладить следующие проблемы:
(используется компилятор MS VC 6.0, то есть версия 12 компилятора Microsoft C)
Первая аномалия:
extern double Time, TimeStamp, TimeStep; // History terms, updated elsewhere
void timer_evaluation_function( ) {
if ( ( Time - TimeStamp ) >= TimeStep ) {
TimeStamp += TimeStep;
timer_controlled_code( );
}
{....}
По какой-то причине оценка таймера завершилась неудачно, а таймерный код никогда не выполнялся. В отладчике не было проблем с тем, чтобы убедиться, что условие триггера действительно выполнялось, но FPU отказался найти положительный результат. Следующий сегмент кода не имел проблем, хотя он выполнял те же операции. Проблема была обойдена путем вставки фиктивной оценки, которая могла быть ошибочной.
Я предполагаю, что состояние FPU как-то испорчено выполненными ранее операциями, и что есть некоторые флаги компилятора, которые могли бы помочь?
Вторая аномалия:
double K, Kp = 1.0, Ti = 0.02;
void timed_code( ){
K = ( Kp * ( float ) 2000 ) / ( ( float ) 2000 - 2.0F * Ti * 1e6 )
{....}
Результат равен #IND, хотя отладчик оценивает уравнение примерно до 0,05. Значение #IND появляется в стеке FPU, когда значение 2.0F загружается в FPU из-за использования инструкции fld. Предыдущая инструкция загружает целочисленное значение 2000 как двойное число с использованием инструкции fild. Как только стек FPU содержит значение #IND, все теряется, но у отладчика снова возникает проблема с вычислением формулы. Позже эти операции возвращают ожидаемые результаты.
Кроме того, снова проблемы с FPU возникают непосредственно после вызова функции. Должен ли я вставлять операции с плавающей запятой, которые очищают состояние FPU после каждой новой функции? Есть ли флаг компилятора, который может как-то повлиять на FPU?
Я благодарен за все советы и рекомендации на данный момент.
РЕДАКТИРОВАТЬ: мне удалось избежать проблемы, вызвав функцию сборки EMMS первым делом в верхней функции. Таким образом, FPU очищается от любого связанного с MMX мусора, который мог или не мог быть создан в среде, из которой вызывается мой код. Похоже, что состояние FPU не является чем-то само собой разумеющимся.
// Франк