Умножение, деление. Что не так?
const unsigned long C1 = 30 * 1000;
const unsigned long C2 = (300 * 1000)/C1; // должно быть = 10
void setup() {
Serial.begin(57600);
Serial.println("\n-------");
Serial.print("C1 = "); Serial.println(C1);
Serial.print("C2 = "); Serial.println(C2);
unsigned long V1 = (300 * 1000)/C1; // должно быть = 10
Serial.print("V1 = "); Serial.println(V1);
long V2 = (300 * 1000)/30000; // должно быть = 10
Serial.print("V2 = "); Serial.println(V2);
int V3 = (300 * 1000)/30000; // должно быть = 10
Serial.print("V3 = "); Serial.println(V3);
}
void loop() {
}
Arduino UNO напечатано в консоли монитора:
C1 = 30000 (ok)
C2 = 143164 (must be = 10)
V1 = 143164 (must be = 10)
V2 = 0 (must be = 10)
V3 = 0 (must be = 10)
Что не так?
@tim4dev, 👍0
Обсуждение4 ответа
Лучший ответ:
300
и
1000
являются целыми числами.
Что
long V2 = (300 * 1000)/30000;
действительно делает, берет целые числа 300 и 1000, умножает их. Это вычисление переполняется и равно -27680. Разделив это на 30000, получаем 0. То, что вы добавили в своем комментарии, не является хаком, это правильное решение. Включая суффикс L или UL, вы сообщаете компилятору, что вам нужны длинные числа, а не целые.
Что не так?
Вы предполагаете, что выражение имеет тип long int, но на самом деле это int. Литералы имеют тип int. Вам нужно убедить компилятор, что выражение имеет тип long int. Это можно сделать с помощью приведения:
((long) 30000)
или синтаксис длинного целого числа:
30000L
Компилятор AVR GCC использует int, определенный как 16-битный. Выражение и литералы подразумевают 16-битные.
Дополнительную информацию о представлении типов данных C/C++, выражений и соглашений о вызовах можно найти здесь.
Ура!
Это мой код для вашей проблемы:
unsigned long mul(long num1, long num2)
{
unsigned long res, add = 0;
while (num1 > 65000)
{
num1 -= 65000;
add++;
}
res = unsigned(num1 * num2);
while(add)
{
res +=65000;
add--;
}
return (res + add);
}
Это не решает никаких проблем, ни для чего не полезно и потенциально может потребовать огромного количества процессорного времени., @Edgar Bonet
Хорошая практика с литеральными числами, которые вы хотите разделить и умножить, — всегда определять их как double
и преобразовывать их в целые числа при их использовании. Это часто имеет место с константами частоты/периода. Это предотвращает большинство катастрофических ошибок переполнения/округления, которые могут возникнуть в целочисленной математике, и в то же время позволяет использовать согласованные единицы измерения в ваших определениях.
#define F_CPU 16000000.0 // в Гц
#define F_TICK (1.0/F_CPU) // в секундах
#define DELAY 0.001 // в секундах
#define COUNT ((uint16)(DELAY/F_TICK))
Serial.println(COUNT);
Конечно, вы можете вычислить количество тактов процессора в миллисекунду, используя математические вычисления с фиксированной запятой, например, определив частоту в МГц и время такта в наносекундах, но вам придется чесать голову каждый раз, когда вам это понадобится. для преобразования периода в частоту и наоборот, и вам придется менять единицы измерения в тот момент, когда ваша частота не будет кратна МГц.
- Поскольку double и float представляют один и тот же тип данных (обычно), что предпочтительнее?
- cast double to long приводит к неожиданным результатам
- Преобразование int или float в массив байтов в ардуино
- Какой тип данных можно использовать для хранения двоичного битового потока, длина которого превышает 64 бита?
- Как объявить массив переменного размера (глобально)
- Программирование Arduino с использованием Python, а не C/C ++
- Загрузка Arduino Nano дает ошибку: avrdude: stk500_recv(): programmer is not responding
- Как справиться с rollover millis()?
Взломайте
long V2 = (300 * 1000UL)/30000;
напечатайте10
, @tim4dev