Jump to content

    

Для 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

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

Share this post


Link to post
Share on other sites

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

UBFX r0,r0,#4,#8

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

Share this post


Link to post
Share on other sites
Деление и сдвиг производятся с помощью одной и той же команды:

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 в конце.

Share this post


Link to post
Share on other sites
Добавьте везде 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 - без знака.

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

Share this post


Link to post
Share on other sites
На эти U L я обычно "ложил с прибором". Да, видно, зря. Не пойму, 16 - оно ж и в Африке 16. Или нет?
Или нет. Без явного указания типа (по умолчанию) все константы имеют знаковый тип signed int.

Share this post


Link to post
Share on other sites
Или нет. Без явного указания типа (по умолчанию) все константы имеют знаковый тип signed int.

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

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

Share this post


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

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

Share this post


Link to post
Share on other sites

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

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 лучше не игнорировать.

Share this post


Link to post
Share on other sites
(x<0) ? ((x+1)>>1): (x>>1)

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

Share this post


Link to post
Share on other sites
Спасибо! Сами не ведая, помогли мне багу найти. :)

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

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

Share this post


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

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

-3 / 2 = -1

-3 = 0b11111101

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

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

Share this post


Link to post
Share on other sites
Вообще говоря методов округления существует больше, чем один.

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

Share this post


Link to post
Share on other sites
... а если его не придерживаться там, где это надо - это бага

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

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

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this