2009-09-08 7 views
4

У меня есть код, написанный на C, который предназначен для 16-разрядного микроконтроллера. В коде существенно много арифметики с плавающей запятой.Вычитание с плавающей запятой в результатах C 0

Арифметика отлично работает до тех пор, пока результат не будет положительным, но в случае вычитания, если ожидаемый результат отрицательный, я получаю нуль.

result = 0.005 - 0.001;  Is correctly computed as 0.004 
result = 0.001 - 0.005;  Is always zero. 

Почему такое поведение при поплавке?

+4

Возможно, у вас есть 'unsigned float'. :) –

ответ

5

Интересно. Это вполне может быть ошибкой в ​​программном обеспечении с плавающей запятой. Встраиваемые системы часто включают с плавающей запятой в качестве опции, чтобы уменьшить размер кода.

Я не уверен, что проблема здесь, хотя с момента вашего первого заявления работает.

Что происходит с:

result = 0.005 - 0.001; 
result = -result; 

result = 0.002 - 0.001; 
result = 0.002 - 0.002; 
result = 0.002 - 0.003; 

result = 0.001 - 0.002; 
result = 0.001 - 0.003; 
result = 0.001 - 0.004; 

Идея заключается в том, чтобы собрать полезную информацию о том, что может быть причиной его, обычная вещь, чтобы сделать в судебно-медицинской экспертизы. Результаты этих вычислений, вероятно, будут полезны при определении фактической проблемы.

Основываясь на результатах в комментариях:

result = 0.005 - 0.001; // 0.004 
result = -result;  // 0.000 
result = 0.002 - 0.001; // 0.001 
result = 0.002 - 0.002; // 0.000 
result = 0.002 - 0.003; // 0.000 
result = 0.001 - 0.002; // 0.000 
result = 0.001 - 0.003; // 0.000 
result = 0.001 - 0.004; // 0.000 

Похоже, ваша библиотека с плавающей точкой имеет серьезный недостаток. Еще два вопроса:

  • Как вы распечатка результатов (показать нам код фактического)?
  • Какой микроконтроллер и среда разработки вы используете?

Возможно, возникла некоторая проблема с тем, как вы печатаете, или это может быть ограничение вашей среды.

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

Основываясь на некоторых из ваших комментариев, а именно:

Адриана, тип данных для «результата» является поплавок, то есть, 32-битное представление (одинарное). У меня есть CAN как системный интерфейс, и поэтому я умножаю результат на 1000, чтобы отправить его по шине CAN. Если это отрицательное число, например -0.003, то я ожидаю FF FD в сообщении CAN. У меня нет отладчика.

Я не уверен, что полностью понимаю, но я дам ему шанс.

У вас есть 32-битная с плавающей точкой, например, -0.003 и умножить ее на 1000 и положить его в целом числе (0xFFFD является 16-разрядным двоичным дополнением представления -3).Так что же происходит, когда вы запускаете что-то вроде следующего кода:

int main(void) { 
    float w = -0.003; 
    int x = (int)(w * 1000); 
    int y = -3; 
    int z = -32768; 
    // Show us you code here for printing x, y and z. 
    return 0; 
} 

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

Если «CAN» - это своего рода последовательный интерфейс, возможно, есть ограничение на байты, которые вам разрешено отправлять через него. Я могу предусмотреть сценарий, в котором высокие байты используются как маркеры пакетов, так что FF может на самом деле закончить сообщение преждевременно. Вот почему я также хочу, чтобы вы протестировали -32768 (0x8000).

Трудно поверить, что STMicroelectronics создаст такую ​​систему времени исполнения, что не сможет обрабатывать отрицательные поплавки. Мне кажется гораздо более вероятным, что информация повреждается где-то в другом месте (например, процесс «печати», что бы это ни было).

+0

Вот наблюдения: результат = 0,005 - 0,001; = 0,004 result = -result; = 0 результат = 0,002 - 0,001; = 0,001 результат = 0,002 - 0,002; = 0 результат = 0,002 - 0,003; = 0 результат = 0,001 - 0,002; = 0 результат = 0,001 - 0,003; = 0 результат = 0,001 - 0,004; = 0 Также результат = 0,01 - 0,04; = 0 результат = 0,01 - 0,05; = 0 – 2009-09-08 08:45:20

+1

Pax, Его контроллер серии ST10. – 2009-09-08 09:02:46

+1

Hey Pax, У меня есть исправление. Как вы сказали, проблем с арифметикой с плавающей запятой вообще нет.Проблема заключается в преобразовании отрицательного float в integer. Для ST10, float w = -0.003; int x = (int) (w * 1000); Результаты в ноль. Правильный метод: 1. float w = -0.003; float a = -w; 2. int b = (int) (a * 1000); 3. int c = -b; Таким образом, «C» будет иметь целое число со знаком, соответствующее отрицательному значению с плавающей запятой. Спасибо за помощь !!!! Cheers :-) – 2009-09-08 17:48:20

0

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

+0

Нет микрочипов, которые не имеют переноски с плавающей точкой. Но вместо этого он имеет библиотеки с плавающей запятой. Из некоторых предыдущих проектов в файле .lib нет ошибки. – 2009-09-08 07:06:39

0

Возможно ли, что вы пытаетесь распечатать результат 0.001 - 0.005 в виде поля с 5 символами? Если это так, результат будет отображаться как округленный до 0.0.

+0

Спасибо Стивен, но я умножаю результат на 1000, чтобы увидеть его как целое. – 2009-09-08 08:46:21

0

Можете ли вы предоставить больше контекста? В этом примере оценка может быть выполнена компилятором, так как обе константы известны во время компиляции. Каков тип «результата»? (т. е. IEEE-754 половина или одна или двойная?) Как вы оцениваете это? С помощью отладчика, if-statement или с printf? Причина, по которой я спрашиваю об этом, состоит в том, что может быть красная селедка. Например, если вы неправильно форматируете использование printf, вы можете просто не видеть знак минус. Когда вы посмотрите на двоичное представление (т. Е. По printf («% lx», result), если оно 32-битное) и проверьте бит знака.

+0

Adriaan, тип данных для «результата» имеет float, то есть 32-битное представление (однократное). У меня есть CAN как системный интерфейс, и поэтому я умножаю результат на 1000, чтобы отправить ti через CAN. Если это отрицательное число, например -0.003, то я ожидаю FF FD в сообщении CAN. У меня нет отладчика. – 2009-09-08 08:52:02

0

Это не неотъемлемо C вещь, так что вплоть до того, что вы не сказали: -

  • Controller (ST10-видимому)
  • Compiler (? Cosmic программное обеспечение Если так соответствует стандартам)
  • Floating библиотека точки (от компилятора?)
  • программа (Кратчайший полная программа, которая показывает, что это будет хорошо.)

Может ли это быть вашим преобразованием с плавающей точкой в ​​int, которое вы не показывали?

+0

Не похоже, потому что тот же код работает, когда результат положительный. Я не могу поделиться с вами программой из-за проблем с IP. простите за это. – 2009-09-08 11:00:04

+0

Неужели вы могли бы сделать короткую форму? Я чувствую, что другие части кода, скорее всего, будут проблемой. Ваши знания о том, что находится в «результате», выведены только в конце. – 2009-09-08 11:48:36

+0

int x = (int) (w * 1000); приводит к нулю Попробуйте 1000.0, он делает неявное преобразование, обрабатывающее 1000 как const int. – 2009-09-09 13:17:53

 Смежные вопросы

  • Нет связанных вопросов^_^