реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> Как проверить, что число не превысило ULLONG_MAX?
ViKo
сообщение Apr 7 2018, 12:25
Сообщение #1


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Допустим, в макрофункции производятся некие вычисления - умножение, деление. И ее результат должен быть больше нуля и меньше или равным 2 ^32.
Как задать параметры макрофункции, чтобы гарантировать, что компилятор при расчетах не вышел за пределы unsigned long long? Если их несколько.
Задачу для ограничений результатов могу так сделать:
(FUN > UINT_MAX) ? UINT_MAX : (FUN > 0 ? FUN : 1)
А проверку внутри макрофункции? Наверное, никак?
Go to the top of the page
 
+Quote Post
HardEgor
сообщение Apr 7 2018, 12:36
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 2 223
Регистрация: 3-03-06
Из: Tomsk
Пользователь №: 14 925



Цитата(ViKo @ Apr 7 2018, 19:25) *
А проверку внутри макрофункции? Наверное, никак?

Для одной или двух переменных еще выгодно проверять входящие, если больше - то дешевле вычислить с большей разрядностью, потому что надо проверять все комбинации границ значений.
Go to the top of the page
 
+Quote Post
ViKo
сообщение Apr 7 2018, 12:37
Сообщение #3


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(HardEgor @ Apr 7 2018, 15:36) *
Для одной или двух переменных еще выгодно проверять входящие, если больше - то дешевле вычислить с большей разрядностью, потому что надо проверять все комбинации границ значений.

Так и хочу, потому и использую ULL. Но как этот предел проверить?
У меня 3 переменных.
Go to the top of the page
 
+Quote Post
HardEgor
сообщение Apr 7 2018, 12:47
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 2 223
Регистрация: 3-03-06
Из: Tomsk
Пользователь №: 14 925



Для каждого выражения свои.
Например х*y/z - чтобы не вышли за 64бита, достаточно чтобы все значения были не более 32 бита
а если х*y*z и значения 32 бита - чтобы не вышли за 64бита, надо контролировать чтобы сумма разрядности чисел не превысила 64, можно логарифмы сложить.
Go to the top of the page
 
+Quote Post
ViKo
сообщение Apr 7 2018, 12:49
Сообщение #5


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Сообразил. Перемежать операции умножения и деления UINT чисел, чтобы промежуточный расчет принципиально не мог выйти за пределы ULLONG числа. Но чтобы и точность не потерялась, смотреть.
Go to the top of the page
 
+Quote Post
HardEgor
сообщение Apr 7 2018, 13:41
Сообщение #6


Гуру
******

Группа: Свой
Сообщений: 2 223
Регистрация: 3-03-06
Из: Tomsk
Пользователь №: 14 925



Я думал, что это подразумевалось sm.gif Но это слишком узкий взгляд - у вас же не все переменные могут получить значения с максимальной разрядностью. Но тут не очень понятна конечная цель.
Go to the top of the page
 
+Quote Post
ViKo
сообщение Apr 7 2018, 14:01
Сообщение #7


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Да, если буду делить не в конце, потеряю точность. Правильнее сначала перемножать, потом логарифмы складывать.
Go to the top of the page
 
+Quote Post
jcxz
сообщение Apr 7 2018, 14:10
Сообщение #8


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Для вычисления константных выражений (видимо их Вы и имели в виду? так как у макроопределений в си нет никаких типов - это просто текстовые подстановки) компилятор использует определённый тип данных, например unsigned long long для целых. И за его пределы он не может выйти естественно никак по определению.
Go to the top of the page
 
+Quote Post
ViKo
сообщение Apr 7 2018, 14:59
Сообщение #9


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(jcxz @ Apr 7 2018, 17:10) *
Для вычисления константных выражений (видимо их Вы и имели в виду? так как у макроопределений в си нет никаких типов - это просто текстовые подстановки) компилятор использует определённый тип данных, например unsigned long long для целых. И за его пределы он не может выйти естественно никак по определению.

Пусть называются константные выражения.
Выйти - отчего же не может? Задам ему 1E12 * 1E12, вот и вышел. Переполнился. Мне нужно знать, что вычисление не переполнилось при обработке препроцессором.
Допустим, как определять, есть идеи. Но как эту проверку встроить в макрофункцию?
#define Delay(V, U) delay(V * U * F / 4 / 10E9)
Здесь можно проверить:
V * U <= 2^32 * 4 * 10E9 / F

P.S. тут я смешиваю два вопроса, проверить, что результат укладывается в целое число, и не допустить, чтобы в процессе вычисления не было переполнения длинного числа.

А есть способ выдать число в Build Output компилятора?

Видимо, вопрос сводится к следующему: Как вставить assert внутрь macro?
Go to the top of the page
 
+Quote Post
ViKo
сообщение Apr 7 2018, 17:19
Сообщение #10


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Хорошо, #warning Keil может вывести, этим можно пользоваться для вывода ограничений на параметры.
Самому считать не придется. Остальное уже не важно.
А вот #error так вывести не получится.
Go to the top of the page
 
+Quote Post
501-q
сообщение Apr 8 2018, 18:45
Сообщение #11


Участник
*

Группа: Участник
Сообщений: 38
Регистрация: 24-02-09
Из: Екатеринбург
Пользователь №: 45 296



Цитата(ViKo @ Apr 7 2018, 19:59) *
Видимо, вопрос сводится к следующему: Как вставить assert внутрь macro?

Код
/* ct-assert.h */


/* макросы проверяют, что ex константа и не 0 */

#if !defined( CT_ASSERT_EXPR )
#define CT_ASSERT_EXPR(ex)  ((struct { int assert:(ex) ? 1 : -1; } *)0 ? 0 : 0)
#endif /* !defined( CT_ASSERT_EXPR ) */

#if !defined( CT_ASSERT_DECL )
#define CT_ASSERT_DECL(ex)  extern char ct_assert_[ CT_ASSERT_EXPR(ex)+1 ]
#endif /* !defined( CT_ASSERT_DECL ) */

#if !defined( CT_ASSERT )
#define CT_ASSERT(ex)       (void)CT_ASSERT_EXPR(ex)
#endif /* !defined( CT_ASSERT ) */


/* End of file  ct-assert.h */

Используй макрос CT_ASSERT_EXPR(). Он всегда равен 0, если скомпилировался без ошибок.

Илья
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 18th July 2025 - 12:52
Рейтинг@Mail.ru


Страница сгенерированна за 0.01442 секунд с 7
ELECTRONIX ©2004-2016