Простая ошибка умножения

Выполнение следующего кода всегда дает -511, в результате я выполнил много тестов, и кажется, что результаты верны от 0 * 0 до 181 * 181, помимо этого результаты ненормальны, я пробовал много типов для z переменная (int, long, float) безуспешно, есть идеи? Я использую Arduino Uno.

long z = 0;

void setup() {

Serial.begin(9600);

}

void loop() {

  z = 255 * 255;
  Serial.println(z);
  delay(200);

} 

, 👍6

Обсуждение

Подсказка: попробуйте «z = 255 * 255L;» или «z = 255 * (длинное) 255;», @Mikael Patel

Я сделал. @MikaelPatel Я действительно работал, не могли бы вы объяснить причину этого, и есть ли подобные случаи для других типов?, @Huskarnov

Эта «ошибка» стара, как программирование. Когда вы пишете «255», компилятор создает «целочисленную константу» со значением 255. Когда вы умножаете 255 на 255, вы умножаете две «целочисленные константы», и по соглашению результатом такого умножения является «целое число». Затем вы неявно приводите его к long при выполнении задания. Когда вы умножаете «255» на «255L», вы фактически умножаете «целочисленную константу» на «длинную константу», и результатом такого умножения является «длинная». Вы столкнетесь с аналогичной проблемой, когда напишете float z = 1/5, результат будет 0, поскольку в результате целочисленного деления получается целое число, которое позже преобразуется в число с плавающей запятой., @Filip Franik

Ссылка: https://gcc.gnu.org/wiki/avr-gcc — это вся информация, необходимая для компилятора AVR GCC. Все это связано с 1) диапазоном чисел «int» для данной цели и 2) оценкой компилятором постоянных выражений., @Mikael Patel

@MikaelPatel Вам следует отвечать на вопросы, а не писать их фрагменты в разделе комментариев., @pipe


2 ответа


0

Предполагая, что длина long равна 4 байтам, это должно работать.

Однако, если по какой-то причине длинный тип имеет длину всего 2 байта, или (что более вероятно) вы использовали другой тип или существует какое-то неправильное определение/определение типа, и это длинный тип со знаком (по умолчанию, если вы не использовали ключевое слово без знака) , диапазон значений составляет от -32 768 до 32 767 и 255 * 255 = 65 025, что выходит за пределы диапазона.

Поэтому сначала можно попробовать использовать unsigned long.

,

длинный — от -2 147 483 648 до 2 147 483 647., @Juraj

Если использовать unsigned long, результат будет: 4294966785., @Huskarnov

Ответ Квасмича правильный, @Juraj

@Юрай - там один короткий :p, @Jaromanda X

@Juraj Я думаю, что такая длина каким-то образом определяется как 2 байта., @Michel Keijzers

это не. Квасмич объясняет, @Juraj


12

Нет, это не ошибка. Вы используете выражение константы времени компиляции, которое имеет вид signed int, если не указано иное. Поэтому вы можете представлять числа только от -32768 до 32767. Ваше вычисление 255 * 255 = 65025 выходит за пределы диапазона. Таким образом, вы видите переполнение. В стандарте C/C++ переполнение знаковых типов на самом деле является неопределённым поведением. Это означает, что компилятору разрешено делать что угодно: от отображения правильного ответа до остановки и возгорания. Только беззнаковые типы с известным размером, например uint16_t, имеют четко определенное поведение при переполнении. Вам следует перевести вычисления правой части в беззнаковый тип следующим образом:

z = 255U * 255U;

Таким образом, вы сообщаете компилятору о своем намерении и не попадаете в «Землю неопределенного поведения».

,

@Juraj Верно, я думал, что он подписан как 16-битный, как int. Но последнее по-прежнему верно. Константы времени компиляции имеют знак int, то есть 16 бит. Итак, проблема заключается в правой части задания., @Kwasmich

«заворачиваться» звучит неправильно, но я знаю, о чем вы говорите, @Jaromanda X