Перейти к содержанию

    

Для uint в Keil /16 не равно >>4

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

;;;222      uint8_t s0, s1, s2, s3;
;;;223      uint8_t m1 = ((s1 + s2) * 9 - s0 - s3) / 16;
000106  eb0c0006          ADD      r0,r12,r6
00010a  eb0000c0          ADD      r0,r0,r0,LSL #3
00010e  eba00007          SUB      r0,r0,r7
000112  eba00006          SUB      r0,r0,r6
000116  ea4f71e0          ASR      r1,r0,#31
00011a  eb007111          ADD      r1,r0,r1,LSR #28
00011e  f3c11107          UBFX     r1,r1,#4,#8
;;;224      uint8_t m2 = ((s1 + s2) * 9 - s0 - s3) >> 4;
000122  f3c01007          UBFX     r0,r0,#4,#8

Округление, что ли?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Добавьте везде volatile, и не будет никакой разницы. Деление и сдвиг производятся с помощью одной и той же команды:

UBFX r0,r0,#4,#8

Результат остальных действий сохраняется в регистрах, и используется в обоих случаях - оптимизация.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
Деление и сдвиг производятся с помощью одной и той же команды:

UBFX r0,r0,#4,#8

Судя по листингу - нет.

Всё-таки деление (в первом случае) почему-то знаковое.

000116  ea4f71e0          ASR      r1,r0,#31
00011a  eb007111          ADD      r1,r0,r1,LSR #28
00011e  f3c11107          UBFX     r1,r1,#4,#8

 

А вот для проверки почему, надо бы ко всем константам приписать U в конце.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
Добавьте везде volatile, и не будет никакой разницы

;;;222      volatile uint8_t s0, s1, s2, s3;
;;;223      volatile uint8_t m1 = ((s1 + s2) * 9 - s0 - s3) / 16;
000106  eb0c0006          ADD      r0,r12,r6
00010a  eb0000c0          ADD      r0,r0,r0,LSL #3
00010e  eba00007          SUB      r0,r0,r7
000112  eba00006          SUB      r0,r0,r6
000116  ea4f71e0          ASR      r1,r0,#31
00011a  eb007111          ADD      r1,r0,r1,LSR #28
00011e  f3c11107          UBFX     r1,r1,#4,#8
;;;224      volatile uint8_t m2 = ((s1 + s2) * 9 - s0 - s3) >> 4;
000122  f3c01007          UBFX     r0,r0,#4,#8

 

А вот для проверки почему, надо бы ко всем константам приписать U в конце.

;;;222      volatile uint8_t s0, s1, s2, s3;
;;;223      volatile uint8_t m1 = ((s1 + s2) * 9U - s0 - s3) / 16U;
000106  eb0c0006          ADD      r0,r12,r6
00010a  eb0000c0          ADD      r0,r0,r0,LSL #3
00010e  eba00007          SUB      r0,r0,r7
000112  eba00006          SUB      r0,r0,r6
000116  ea4f1010          LSR      r0,r0,#4
00011a  b2c1              UXTB     r1,r0
;;;224      volatile uint8_t m2 = ((s1 + s2) * 9U - s0 - s3) >> 4U;
00011c  b2c0              UXTB     r0,r0

Вы правы...

 

На эти U L я обычно "ложил с прибором". Да, видно, зря. Не пойму, 16 - оно ж и в Африке 16. Или нет?

 

Еще варианты

;;;222      volatile uint8_t s0, s1, s2, s3;
;;;223      volatile uint8_t m1 = ((s1 + s2) * 9U - s0 - s3) / 16;
000106  eb0c0006          ADD      r0,r12,r6
00010a  eb0000c0          ADD      r0,r0,r0,LSL #3
00010e  eba00007          SUB      r0,r0,r7
000112  eba00006          SUB      r0,r0,r6
000116  ea4f1010          LSR      r0,r0,#4
00011a  b2c1              UXTB     r1,r0
;;;224      volatile uint8_t m2 = ((s1 + s2) * 9U - s0 - s3) >> 4;
00011c  b2c0              UXTB     r0,r0

;;;222      volatile uint8_t s0, s1, s2, s3;
;;;223      volatile uint8_t m1 = ((s1 + s2) * 9 - s0 - s3) / 16U;
000106  eb0c0006          ADD      r0,r12,r6
00010a  eb0000c0          ADD      r0,r0,r0,LSL #3
00010e  eba00007          SUB      r0,r0,r7
000112  eba00006          SUB      r0,r0,r6
000116  f3c01107          UBFX     r1,r0,#4,#8
;;;224      volatile uint8_t m2 = ((s1 + s2) * 9 - s0 - s3) >> 4U;
00011a  f3c01007          UBFX     r0,r0,#4,#8

Да, приходит понимание, что 16 - это число со знаком, а 16U - без знака.

Спасибо! Похоже, виновник найден.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
На эти U L я обычно "ложил с прибором". Да, видно, зря. Не пойму, 16 - оно ж и в Африке 16. Или нет?
Или нет. Без явного указания типа (по умолчанию) все константы имеют знаковый тип signed int.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
Или нет. Без явного указания типа (по умолчанию) все константы имеют знаковый тип signed int.

Понял. Осознал. Искуплю. :)

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

Поделиться сообщением


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

Такова селяви. В соответствии со стандартом при выполнении арифм. операций в случае, когда один операнд знаковый, а другой - беззнаковый, производится приведение к беззнаковому типу.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

И все-же, я не уверен, что этот код

000116  ea4f71e0          ASR      r1,r0,#31
00011a  eb007111          ADD      r1,r0,r1,LSR #28
00011e  f3c11107          UBFX     r1,r1,#4,#8

есть расширение знака при делении на 16.

Может, все-таки, округление?

upd. Всё, нашел! В книге "ARM System Developer’s Guide" имеется точный ответ.

 

If your code uses addition, subtraction, and multiplication, then there is no performance

difference between signed and unsigned operations. However, there is a difference when it

comes to division. Consider the following short example that averages two integers:

int average_v1(int a, int B )

{

return (a+B )/2;

}

This compiles to

average_v1

ADD r0,r0,r1 ; r0 = a + b

ADD r0,r0,r0,LSR #31 ; if (r0<0) r0++

MOV r0,r0,ASR #1 ; r0 = r0>>1

MOV pc,r14 ; return r0

Notice that the compiler adds one to the sum before shifting by right if the sum is

negative. In other words it replaces x/2 by the statement:

(x<0) ? ((x+1)>>1): (x>>1)

 

В-общем, при делении на положительную константу U лучше не игнорировать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
(x<0) ? ((x+1)>>1): (x>>1)

Спасибо! Сами не ведая, помогли мне багу найти. :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
Спасибо! Сами не ведая, помогли мне багу найти. :)

Может быть, и не только вам :) Себе, так уж точно.

Книжка эта есть "в закромах". Просто бомба, а не книжка. (неуместное сравнение, извиняюсь!) Настоящая Библия! Жаль, что не про Cortex.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
В-общем, при делении на положительную константу U лучше не игнорировать.

Никогда об этом не задумывался. Спасибо!

-3 / 2 = -1

-3 = 0b11111101

(0b11111101 + 1)/2 = 0b11111110/2 = 0b11111111 = -1 верно!

(0b11111101 + 0)/2 = 0b11111101/2 = 0b11111110 = -2  неверно!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
Вообще говоря методов округления существует больше, чем один.

дело в де-факто стандарте, а не в методах, а если его не придерживаться там, где это надо - это бага, имхо, вылезет она сразу или существенно позже..

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
... а если его не придерживаться там, где это надо - это бага

Что за бага? И кто багописатель?

У ViKo никаких багов не было.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти
Авторизация