Jump to content

    
Bpovov

Преобразование знаковых типов

Recommended Posts

Добрый день друзья! 

Уже лет 15 не писал для AVR-ных камней, но тут потребовалось вспоминать атмежку8)) ностальгия блин) но возникла проблема....

есть выражение

signed long a;

signed int b, c, final;

unsigned char d;

a= ((b-c)*100)/d;

final = a;

Внутри выражения(a=....) промежуточные значения могут быть на бОльшую часть диапазона signed long, но гарантированно без переполнения. Конечное же значение записываемое в a, гарантированно без переполнения попадает в диапазон signed int. Поэтому чтобы дальше работать с более короткой переменной,  я решил переписать результат в final, который signed int. 

При проверки на железе в final по факту ахинея, а в "а" все верно. Т.е. косяк в преобразовании типов. В unsigned там все  просто преобразовывается. А с signed что то не придумать.

Подскажите пожалуйста, заранее спасибо!

Share this post


Link to post
Share on other sites

16 , 15 числовых 1 знаковый

ну кстати и логично что ничего не меняет

скомпилированный кусок асма  одиноков  и для 

final = (signed int)a;

и для

final = a;

..........

 

                LDS  R30,_a

                LDS  R31,_a+1

                STS  _final ,R30

                STS  _final ,R31

..........

 

т.е. ничего не поменялось и насколько я понимаю, как раз копируются просто два младших байта, а информация о знаке которая храниться в 4 байте long'а (переменной "a") теряется.... вроде верно мыслю?

Edited by Bpovov

Share this post


Link to post
Share on other sites

Вот собственно весь кусок кода что наассемблир комплилятор, как мне кажется тут косяк уже даже в самом выражении (напомню промежуточные значения ну то есть (Current_Position_uV - Mas_position[9])*100)) могут быть больше signed int.

#define TIME_DELAY_MEAS     416

signed long Current_Speed_actuator_Buf;

signed int Current_Speed_actuator, Current_Position_uV,  Mas_position[10];

 

////////////////Current_Speed_actuator_Buf = (((Current_Position_uV - Mas_position[9])*100) / TIME_DELAY_MEAS);

                __GETW1MN _Mas_position,18

                LDS  R26,_Current_Position_uV

                LDS  R27,_Current_Position_uV+1

                SUB  R26,R30

                SBC  R27,R31

                LDI  R30,LOW(100)

                LDI  R31,HIGH(100)

                CALL __MULW12

                MOVW R26,R30

                LDI  R30,LOW(416)

                LDI  R31,HIGH(416)

                CALL __DIVW21

                CALL __CWD1

                STS  _Current_Speed_actuator_Buf,R30

                STS  _Current_Speed_actuator_Buf+1,R31

                STS  _Current_Speed_actuator_Buf+2,R22

                STS  _Current_Speed_actuator_Buf+3,R23

/////////////////////////Current_Speed_actuator = (signed int)Current_Speed_actuator_Buf;

                LDS  R30,_Current_Speed_actuator_Buf

                LDS  R31,_Current_Speed_actuator_Buf+1

                STS  _Current_Speed_actuator,R30

                STS  _Current_Speed_actuator+1,R31

 

 

    .MACRO __GETW1MN
    LDS  R30,@0+(@1)
    LDS  R31,@0+(@1)+1
    .ENDM

__ANEGW1:

                NEG  R31

                NEG  R30

                SBCI R31,0

                RET

 

__LSLW2:

                LSL  R30

                ROL  R31

                LSL  R30

                ROL  R31

                RET

 

__CWD1:

                MOV  R22,R31

                ADD  R22,R22

                SBC  R22,R22

                MOV  R23,R22

                RET

 

__MULW12U:

                MUL  R31,R26

                MOV  R31,R0

                MUL  R30,R27

                ADD  R31,R0

                MUL  R30,R26

                MOV  R30,R0

                ADD  R31,R1

                RET

 

__MULW12:

                RCALL __CHKSIGNW

                RCALL __MULW12U

                BRTC __MULW121

                RCALL __ANEGW1

__MULW121:

                RET

 

__DIVW21U:

                CLR  R0

                CLR  R1

                LDI  R25,16

__DIVW21U1:

                LSL  R26

                ROL  R27

                ROL  R0

                ROL  R1

                SUB  R0,R30

                SBC  R1,R31

                BRCC __DIVW21U2

                ADD  R0,R30

                ADC  R1,R31

                RJMP __DIVW21U3

__DIVW21U2:

                SBR  R26,1

__DIVW21U3:

                DEC  R25

                BRNE __DIVW21U1

                MOVW R30,R26

                MOVW R26,R0

                RET

 

__DIVW21:

                RCALL __CHKSIGNW

                RCALL __DIVW21U

                BRTC __DIVW211

                RCALL __ANEGW1

__DIVW211:

                RET

 

__CHKSIGNW:

                CLT

                SBRS R31,7

                RJMP __CHKSW1

                RCALL __ANEGW1

                SET

__CHKSW1:

                SBRS R27,7

                RJMP __CHKSW2

                COM  R26

                COM  R27

                ADIW R26,1

                BLD  R0,0

                INC  R0

                BST  R0,0

__CHKSW2:

                RET

Edited by Bpovov

Share this post


Link to post
Share on other sites
10 часов назад, Bpovov сказал:

Внутри выражения(a=....) промежуточные значения могут быть на бОльшую часть диапазона signed long

Но компилятор-то об этом не знает. Для него есть четкое правило: signed int * signed int = signed int. Если же у вас результат в signed int не укладывается - вам нужно делать signed long * signed long = signed long. Для этого необходимо хотя бы один из сомножителей привести к signed long. Второй сомножитель будет приведен неявно согласно правилам неявных приведений целых типов (integer promotion rules). То есть ваше выражение должно выглядеть так: 

a = (unsigned long)(b-c) * 100 / d;

или так:

a = (b-c) * 100L / d;

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

10 часов назад, Bpovov сказал:

При проверки на железе в final по факту ахинея, а в "а" все верно

Как вы это наблюдали?

Share this post


Link to post
Share on other sites
10 часов назад, Bpovov сказал:

#define TIME_DELAY_MEAS     416

... 

////////////////Current_Speed_actuator_Buf = (((Current_Position_uV - Mas_position[9])*100) / TIME_DELAY_MEAS);

Зачем вообще тут умножение, а потом деление, если можно просто один раз умножить на (100/TIME_DELAY_MEAS) представив его в виде fixed-point целого?

И проблем с переполнением будет меньше и скорей всего будет быстрее.

Типа:

Current_Speed_actuator_Buf = (long)(Current_Position_uV - Mas_position[9]) * (long)((100ul << 16) / TIME_DELAY_MEAS) >> 16;

Это если нет проблем с переполнением диапазона int в (Current_Position_uV - Mas_position[9]). Если есть, то (как писал Сергей Борщ) - привести аргументы разности к long, а не её результат.

Share this post


Link to post
Share on other sites
7 минут назад, jcxz сказал:

Зачем вообще тут умножение, а потом деление, если можно просто один раз умножить на (100/TIME_DELAY_MEAS) представив его в виде fixed-point целого? И проблем с переполнениями будет меньше и скорость выполнения - быстрее.

#define TIME_DELAY_MEAS     416

целое число меньше 1 получится

Share this post


Link to post
Share on other sites
11 часов назад, Bpovov сказал:

signed long a;

signed int b, c, final;

unsigned char d;

a= ((b-c)*100)/d;

final = a;

Внутри выражения(a=....) промежуточные значения могут быть на бОльшую часть диапазона signed long

Это как так???  :wacko2:

А каков размер long в вашем компиляторе? Его размер что-ли равен размеру int??

Если он больше (если int - 16 бит, а long - 32), то никак такого не может быть (не может никакой промежуточный результат занимать бОльшую часть диапазона long).

Если sizeof(int)==sizeof(long), то моё выражение выше неприменимо. Да и ваши выражения - тоже.  :unknw:

 

5 минут назад, HardEgor сказал:

#define TIME_DELAY_MEAS     416

целое число меньше 1 получится

И что? Почитайте в гугле что такое "fixed-point integer".

Share this post


Link to post
Share on other sites
15 hours ago, Bpovov said:

а информация о знаке которая храниться в 4 байте long'а (переменной "a") теряется.... вроде верно мыслю?

Нет. Гуглите представление отрицательных чисел в двоично дополнительном коде (можете считать, что знак у вашего a в 2х старших байтах + старший бит в 1м байте)

 

Если у вас в a правильное значение, а в final - мусор, то у вас результат не влезает в int (что бы вы не утверждали по этому поводу)

Share this post


Link to post
Share on other sites

Короче что бы я не делал компилятор ни явно ни неявно не захотел адекватно приводить int к long и наоборот, т.е. пришлось где то все на long делать - потерял быстродействие, а где то на асме вручную прописывать байтовые действия с постоянным держанием в нулях старших байтов и контроль знака для int...  Просто уже отвык от такого))  во всяких современных кортексах  А-шках,  с этим проблем нет)))

Edited by Bpovov

Share this post


Link to post
Share on other sites
3 часа назад, Bpovov сказал:

во всяких современных кортексах  А-шках,  с этим проблем нет)))

Компиляторы там подчиняются абсолютно тем же правилам. Так что проблемы будут те же самые.

3 часа назад, Bpovov сказал:

Короче что бы я не делал компилятор ни явно ни неявно не захотел адекватно приводить int к long и наоборот

Правила там просты и совершенно конкретны. Лучше разобраться с ними раз и навсегда, ведь это не последняя ваша программа. А мы поможем по мере сил.

Share this post


Link to post
Share on other sites
20.11.2020 в 15:01, Сергей Борщ сказал:

Компиляторы там подчиняются абсолютно тем же правилам. Так что проблемы будут те же самые.

Правила там просты и совершенно конкретны. Лучше разобраться с ними раз и навсегда, ведь это не последняя ваша программа. А мы поможем по мере сил.

Вот такая штука к примеру, в кейле даже на кортекс М работает верно, без залезания в асм

int A, B;

long C;

А = B*C;  при условии что результат и значения операндов не вылезают за int

 

Share this post


Link to post
Share on other sites
29 минут назад, Bpovov сказал:

Вот такая штука к примеру, в кейле даже на кортекс М работает верно, без залезания в асм

Наверняка она и на компиляторе AVR работает не менее верно, чем на Cortex-M.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.