Операции с переменными разных типов

Ivanii
Offline
Зарегистрирован: 11.10.2015
Уже ранее сталкивался с неоднозначнми результатами при использовании в выражении переменных разных типов, притом даже одинаковые выражения с одинаковыми переменными в разных местах программы давали разныее результаты.
 
На данный момент потребовалось нормально посчитать SIN((micros()/20000+a/3)*2*PI()) , micros() имеет тип unsigned long, другие 4 int и последний float.
 
Подскажите пожалуйста как правильно это записывать не теряя быстродействия, памяти и получать прогнозируемый результат?
NeiroN
NeiroN аватар
Offline
Зарегистрирован: 15.06.2013
SIN((float)(((float)micros()/20000.0)+((float)a/3.0))*2*PI())

можно так попробовать.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Ivanii пишет:

Уже ранее сталкивался с неоднозначнми результатами при использовании в выражении переменных разных типов, притом даже одинаковые выражения с одинаковыми переменными в разных местах программы давали разныее результаты.
 
 
Это совершенно естественное поведение.
Если у нас, скажем, выражение a+b, то очевидно, что при значениях a=1 и b=2 значение выражения составит 3, а при значениях a=2 и b=3 значение выражения составит 5.
 
 
Цитата:
На данный момент потребовалось нормально посчитать SIN((micros()/20000+a/3)*2*PI()) , micros() имеет тип unsigned long, другие 4 int и последний float.
 
Подскажите пожалуйста как правильно это записывать не теряя быстродействия, памяти и получать прогнозируемый результат?

Видите ли, программа работает в точности так, как ее написал программист, но не так, как он хотел написать. Такое объяснение объясняется просто: компилятор ничего не знает о желаниях программиста. Возможно, для Вас это будет новостью, но другие программисты, так же, как и компилятор, не осведомлены о Ваших желаниях, поэтому тоже могут судить лишь о том, что Вы написали, но не о том, что хотели написать.

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

Ivanii
Offline
Зарегистрирован: 11.10.2015

andriano пишет:

Видите ли, программа работает в точности так, как ее написал программист, но не так, как он хотел написать. Такое объяснение объясняется просто: компилятор ничего не знает о желаниях программиста. Возможно, для Вас это будет новостью, но другие программисты, так же, как и компилятор, не осведомлены о Ваших желаниях, поэтому тоже могут судить лишь о том, что Вы написали, но не о том, что хотели написать.

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

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

В версиях выше 1.5 это сломанно притом рандомно - 4 одинаковых условия с одинаково обьявленными переменными, а правильно считается только первое, при переходе от версии к версии грабли вылезают в разных местах.

Вопрос заключается в том как правильно, не раздувая код указать компилятору преобразование типов и/или сразу часть переменных сделать нужного типа?

П.С. в формуле в шапке ошибка связанная с нежелательным преобразованием типов, на данный момент SIN(float((micros() % period) + n[f])/period1) , все переменные кроме "period1" unsigned long, "period1" float.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ivanii пишет:

... так было в версиях до 1.0.

В версиях выше 1.5 это сломанно притом рандомно - 4 одинаковых условия с одинаково обьявленными переменными, а правильно считается только первое, при переходе от версии к версии грабли вылезают в разных местах.

Вы чего-то очень серьёзно не поняли или поняли не так. Компилятор всегда работал одинаково и сейчас работает также, а текст, который я процитировал, является параноидальным бредом. Вам нужно разобраться в этом вопросе иначе будете постоянно наступать на грабли "в разных местах".

Ivanii
Offline
Зарегистрирован: 11.10.2015
ЕвгенийП пишет:
Вы чего-то очень серьёзно не поняли или поняли не так. Компилятор всегда работал одинаково и сейчас работает также, а текст, который я процитировал, является параноидальным бредом. Вам нужно разобраться в этом вопросе иначе будете постоянно наступать на грабли "в разных местах".
 
У меня есть старые скетчи которые после компилирования новым компилятором перестали адекватно работать на железе и лечится это именно расстановкой типов - это явно изменения в компиляторе.
 
У друга скетчи отлаженные прошлым летом в этом январе скомпилированные свежей средой Ардуино также потребовали расстановки/преобразования типов...
 
Вот выдержки для Си:
 
"Преобразования типов
 
Если операнды оператора принадлежат разным типам, то они приводятся к некоторому общему типу. Приведение выполняется в соответствии с небольшим числом правил. Обычно автоматически производятся лишь те преобразования, которые без какой-либо потери информации превращают операнды с меньшим диапазоном значений в операнды с большим диапазоном значений, как, например, преобразование целого в число с плавающей точкой в выражении вроде . Выражения, не имеющие смысла, например число с плавающей точкой в роли индекса, не допускаются. Выражения, в которых могла бы теряться информация (скажем, при присваивании длинных целых переменным более коротких типов или при присваивании значений с плавающей точкой целым переменным), могут повлечь предупреждение, но они допустимы."
 
"При арифметических операциях с разными типами данных происходит автоматическое преобразование типов данных. Но лучше всегда использовать явное преобразование."
 
Могу с уверенностью сказать, что арифметические операции с int и unsigned long работают раз через 3...
 
На данный момент получилось SIN(float((micros() % period) + n[f])/period1) , "period1" float, "f" int, остальные unsigned long, так будет адекватно работать?
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Не, ну я же так и сказал, что Вычего-то очень серьёзно не поняли или поняли не так. 

Ivanii пишет:

У меня есть старые скетчи которые после компилирования новым компилятором перестали адекватно работать на железе и лечится это именно расстановкой типов - это явно изменения в компиляторе.
 
...
 
Могу с уверенностью сказать, что арифметические операции с int и unsigned long работают раз через 3...
 

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

То, что IDE-шный препроцессор меняется, так компилятор тут не при делах.

Ivanii пишет:

На данный момент получилось SIN(float((micros() % period) + n[f])/period1) , "period1" float, "f" int, остальные unsigned long, так будет адекватно работать?

Вам выше коллега сказал, что пока Вы не объясните чего Вы хотите достичь, невозмжно ответить на вопрос "адекватно" то, что Вы пишете или "не адекватно". Хотя, тут сразу видно, что преобразование к float здесь абсолютно лишнее. Но и не помешает (если Вы реально хотите к float преобразовывать).

 

Ivanii
Offline
Зарегистрирован: 11.10.2015

ЕвгенийП пишет:
объясните чего Вы хотите достичь

Получить синус от времени(micros()) с периодом period со сдвигом фазы n[f]
unsigned long n1=0;
unsigned long period=20000;
float period1=float(period)/6.283;
int f = 1;
----
                   (     unsigned long        )
float x = SIN(float((micros() % period) + n[f])/period1);

П.С. У меня оказывается опять старый IDE 1.6.12, актуальная версия 1.8.1, а виндам всего 3 месяца...

Иногда размер кода зависит от версии !плат! и отличается на 200+ байт! (1.6.9 - 1.6.14)

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

1. не понял, что написано в строке 6

2) не нашёл описание массива n

Ivanii
Offline
Зарегистрирован: 11.10.2015
1 пояснение где тип переменных "unsigned long"
 
2 в нем 1 переменная n1
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ivanii пишет:

1 пояснение где тип переменных "unsigned long"
 

Странно, вроде не комментарий.

Ivanii пишет:

 
2 в нем 1 переменная n1

Как он описан? 

Ivanii
Offline
Зарегистрирован: 11.10.2015
1 Это не текст программы, а загатовка.
2 Никак, вопрос не в массиве а в типах переменных, пусть будет так.
7 float x = SIN(float((micros() % period) + n1)/period1);
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ivanii пишет:

2 Никак, вопрос не в массиве а в типах переменных, пусть будет так.

А массив - он не переменная? У него типа нет7 Или его ти нни на что не влияет?

Ivanii пишет:

7 float x = SIN(float((micros() % period) + n1)/period1);

Ну, если так, то, вроде нормально, но float() явно лишнее. Хотя, и не мешает.

 

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Ivanii пишет:

Иногда размер кода зависит от версии !плат! и отличается на 200+ байт! (1.6.9 - 1.6.14)

Это вполне естественно. Более того, это является основой концепции языков высокого уровня.

Кстати, если бы Вы потрудились попробовать на всех платах Ардуино, то вместо "отличается на 200+ байт" написали бы "отличается на десятки килобайт".

Ivanii
Offline
Зарегистрирован: 11.10.2015
Железка одна - UNO, версия IDE и библиотек совпадают, различаются только версии описаний плат 1.6.9 - 1.6.14 , на более новой кода на 230 байт больше...
 
Вот пример на простой мигалке