Почему строка x = 60 * 1000 / 10 вычисляется некорректно ?
- Войдите на сайт для отправки комментариев
Пт, 01/04/2022 - 11:18
Добрый день!
Помогите пожалуйста понять в чем проблема.
word a; word b; word c; word x; void setup() { Serial.begin(9600); } void loop() { x = 60000 / 10; Serial.println(x); // Выдаёт 6000 x = 60 * 1000 / 10; Serial.println(x); // Выдаёт 64983 a = 60; b = 1000; c = a*b; x = c / 10; Serial.println(x); // Выдаёт 6000 delay(1000); }
Почему строка x = 60 * 1000 / 10 вычисляется не корректно?
Что я делаю не так?
Что я делаю не так?
Не учу типы данных, преобразования типов.
Что я делаю не так?
Нафига тут word? Замените на uint16t и все будет работать.
На будущее - старайтесь не использовать псевдонимы типов, такие как byte, word, int и тд. Указывайте типы переменных однозначно - uint8t, uint16t, int32t . Этим вы убережете себя от таких вот "сюрпризов", как в коде выше.
Не учу типы данных, преобразования типов.
а конкретнее?
т.е. для 60000 / 10 тип данных word подходит
а для 60 * 1000 / 10 не подходит?
т.е. для 60000 / 10 тип данных word подходит
а для 60 * 1000 / 10 не подходит?
Подходит.
Не подходит.
word - это результат, но прежде математика. Распишите типы для всех операндов и поиграйтесь.
Не учу типы данных, преобразования типов.
а конкретнее?
т.е. для 60000 / 10 тип данных word подходит
а для 60 * 1000 / 10 не подходит?
че, неужели еще не дошло?
Что я делаю не так?
поставил uint16_t - результат тот же
нет... мой мозг отказывается воспринимать тот факт, что эти строки могут вычисляться по-разному
прошу пояснений или ссылку на какую-нибудь статью с пояснениями )
поставил uint16_t - результат тот же
да, я тоже слошил. Строчку 14 вот так запиши:
x = 60 * 1000u / 10;
или вот так:
x = 60 *( 1000 / 10);
теперь догадался?
заработало, но я всё равно нифига не понял )
можно пояснения пожалуйста? )
можно пояснения пожалуйста? )
В Си по умолчанию все числовые константы без суффиксов имеют тип int
а суффикс u указывает, что это дробный тип?
т.е. 60 * 1000.0 / 10 - тоже заработает....
но почему 60000 / 10 он нормально делит, без суффиксов?
если по-простому, по умолчанию все вычисления в Си происходят в типе signed int. Для ардуины это соответвует типу int16t с диапазоном значений - 32768 ... 32767
В твоем выражении
x = 60 * 1000 / 10;
сначала вычисляется произведение, оно сразу превышает предел типа int16 и происходит переполнение
Спецификатор u у любого из операторов сразу переводит выражение в тип uin16. где диапазон уже 0..65536. Твое произведение помещается, в итоге все считается корректно.
Или просто добавить скобки
а суффикс u указывает, что это дробный тип?
ой.... не надо так откровенно тупить. Есть же гугль. Прежде чем написать глупость, сделал бы поиск
если по-простому, по умолчанию все вычисления в Си происходят в типе signed int. Для ардуины это соответвует типу int16t с диапазоном значений - 32768 ... 32767
В твоем выражении
x = 60 * 1000 / 10;
сначала вычисляется произведение, оно сразу превышает предел типа int16 и происходит переполнение
Спецификатор u у любого из операторов сразу переводит выражение в тип uin16. где диапазон уже 0..65536. Твое произведение помещается, в итоге все считается корректно.
Или просто добавить скобки
вот теперь понял, спасибо....
я думал вычисление идёт в том же диапазоне, что и переменная, в которую записывается результат
по крайней мере в pascal'е и delphi (которые я изучал в институте) это работало так, если мне не изменяет память
ой.... не надо так откровенно тупить. Есть же гугль. Прежде чем написать глупость, сделал бы поиск
всё всё всё, сообразил... u - unsigned
а 1000.0 - преобразует в float, в который 60000 так же умещается
Ещё раз спасибо, затуп конечно знатный, признаю. Был абсолютно убежден, что вычисления ведутся в диапазоне переменной, в которую записывается результат... это и ввело меня в небывалый ступор )
Ещё раз спасибо, затуп конечно знатный, признаю. Был абсолютно убежден, что вычисления ведутся в диапазоне переменной, в которую записывается результат... это и ввело меня в небывалый ступор )
да не, все нормально. Эта ловушка очень типичная, в нее многие попадаются
_Igor_ потому что результат уходит в word и только потом выводится ...
да
Почему эта тема все ещё в не в разделе Песочница?)
вот теперь понял, спасибо....
я думал вычисление идёт в том же диапазоне, что и переменная, в которую записывается результат
по крайней мере в pascal'е и delphi (которые я изучал в институте) это работало так, если мне не изменяет память
Неа, не понял ты...
я думал вычисление идёт в том же диапазоне, что и переменная, в которую записывается результат
Значить, Вы не умеете логично думать.
Другими словами, прежде, чем читать что-либо по программированию, Вам бы ознакомиться с основами логики.
по крайней мере в pascal'е и delphi (которые я изучал в институте) это работало так, если мне не изменяет память
Значит, кроме логики еще и с памятью проблемы.
1. А у вас я вижу проблемы с социальными навыками и недержанием. Непременно нужно пукнуть и сотрясти воздух (в уже решенной теме) своим, несомненно "важным" мнением, дабы всем показать свою восхитительность;
2. В том, в каком диапазоне производятся вычисления нет никакой логической последовательности. Это решение разработчиков, основанное на их каких-то субъективных суждениях. Они могли так же представлять все константы в типе long или char. Такие вещи не выводятся логическими рассуждениями - их просто надо знать.
3. С памятью у меня, как выяснилось, проблемы небольшие. Специально не поленился и скачал паскаль, чтобы перепроверить. Объявляем переменную "a" с типом "word" и пытаемся присвоить ей три разных значения:
a:=(60 * 1000) div 10 - возвращает корректные 6000
a:=(6000 * 1000) div 10 - выдаёт ошибку "constant out of range" - говорящую о том, что значение не помещается в переменную
a:=(6000000 * 1000) div 10 - выдает ошибку Overflow in arithmetic operation
Суть моего "отпечатка в памяти" была в том, что с аналогичными проблемам в паскале я никогда не ставился, так как он при переполнении выдаёт однозначные ошибки, говорящие о том, где переполнение.
Чуть-чуть ошибся в том, что диапазон вычислений не равен диапазону переменной, а он составляет тип longint - поэтому я в него никогда ранее не упирался.
И то, что С++ продолжает свои вычисления, несмотря на переполнения - для моего мозга, взращенного Паскалем, по прежнему нонсенс, хоть я и осознаю, что в этом есть и свои плюсы. Потребуется какое-то время, чтобы с этим смириться. Если вы всю жизнь мешаете чай против часовой стрелки и вам вдруг скажут "мешай по часовой" - для вас это тоже первое время будет не просто...
И ещё раз отмечу - что в данном случае логика совершенно не при чем, это особенности языков, которые НУЖНО ЗНАТЬ. Так что ваш опус был тут совершенно ни к чему
Суть моего "отпечатка в памяти" была в том, что с аналогичными проблемам в паскале я никогда не ставился
Вот тут и суть - Паскаль это учебный язык, а си++ - боевой.
ЗАДАЧА: Прострелить себе ногу.
C: Вы простреливаете себе ногу.
C++: Вы случайно создаете дюжину копий объекта «вы» и всем им простреливаете ногу. Срочная медицинская помощь оказывается невозможной, так как вы не можете разобраться, где настоящие копии, а где — те, что только указывают на них и говорят: «А вот он я!»
Pascal: Компилятор не позволит вам прострелить себе ногу.
с аналогичными проблемам в паскале я никогда не ставился, так как он при переполнении выдаёт однозначные ошибки, говорящие о том, где переполнение.
При компиляции кода из #0 и Arduino IDE однозначно предупреждает, говоря о том, где переполнение:
Вот тут и суть - Паскаль это учебный язык, а си++ - боевой.
Ну вот и пытаюсь переучиваться потихоньку и такие моменты вводят в ступор. Все с чего-то начинали и у всех по первой были детские ошибки и затупы из-за незнания тех или иных особенностей.
А уникумы вроде andriano доводят до белого каления, как будто он из мамки вылез и заговорил сразу на языке С
При компиляции кода из #0 и Arduino IDE однозначно предупреждает, говоря о том, где переполнение:
У меня при компиляции никаких сообщений не выдаётся вообще. Если было как вы показываете - я бы может и сам сообразил
В настройках: «Сообщения компилятора» -> «Все»