Как заставить компилятор продвигать переменную для плавания при выполнении математики - PullRequest
2 голосов
/ 20 мая 2019

У меня есть вопрос о математике в C, быстрый пример ниже:

uint32_t desired_val;
uint16_t target_us=1500
uint32_t period_us=20000;
uint32_t tempmod=37500;


desired_val = (((target_us)/period_us) * tempmod);

В данный момент (target_us / period_us) приводит к 0, который дает требуемый_значение также 0. Я не хочу делать эти переменныеплавать, если я действительно не должен.Мне ничего не нужно после запятой, поскольку она будет сохранена в 32-битном регистре.

Можно ли получить правильные результаты из этого уравнения, не объявляя target_us или period_us как float?Я хочу сделать вычисления с фиксированной запятой, когда это возможно, и с плавающей запятой, когда это необходимо.

Работа на Cortex-M4, если это поможет.

Ответы [ 3 ]

3 голосов
/ 20 мая 2019

Сначала сделайте умножение.

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

uint64_t tempprod = (uint64_t)target_us * tempmod;
desired_val = tempprod / period_us;

Я также использовал uint64_t для временного, на случай переполнения продукта. Существует проблема, если желаемое значение не помещается в 32 бита; надеюсь, данные исключают это.

0 голосов
/ 20 мая 2019

Вы можете сделать вычисления с помощью double довольно легко:

desired_val = (double)target_us  * tempmod / period_us;

float было бы ошибкой, поскольку у него слишком мало точности, чтобы быть надежным.

Возможно, вы захотите округлить это значение до ближайшего целого числа, а не обрезать его:

#include <math.h>
desired_val = round((double)target_us  * tempmod / period_us);

См. Человек вокруг

Конечно, вы могли бы выполнять вычисления, используя более широкий целочисленный тип (например, заменив double на int64_t или long long). Это сделает округление немного сложнее.

0 голосов
/ 20 мая 2019

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

desired_val = ((uint64_t)target_us * tempmod) / period_us;

или выполнить вычисления с плавающей запятой:

desired_val = (uint32_t)(((double)target_us / period_us) * tempmod);
...