View previous topic :: View next topic |
Author |
Message |
kmp84
Joined: 02 Feb 2010 Posts: 363
|
int32 overflow |
Posted: Tue Apr 14, 2020 9:23 am |
|
|
Hello,
What will be the easy way to check "unsigned int32" overflow?
I have multiplication with two "unsigned int32" variable and want to check if result overflow instead show wrong value.
Best Regards! |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19590
|
|
Posted: Tue Apr 14, 2020 10:11 am |
|
|
What processor family?. PIC16, 18, 24, 30 etc..
If you are using a PIC24, 30 or 33, you can use 'mul' which will produce
an int64 result. You can then test this against the maximum limit for
the int32.
On the smaller PIC's, it has been discussed here in the past that the
status register bits do reflect the result of the MSB operation after a
sum. So though rather 'unwanted' to be using low level operations like
this, it is possible to use these:
<https://www.ccsinfo.com/forum/viewtopic.php?p=144142> |
|
|
kmp84
Joined: 02 Feb 2010 Posts: 363
|
|
Posted: Tue Apr 14, 2020 12:00 pm |
|
|
Now I'm testing on PIC16F1459 but for future project will use PIC18.
Some test code:
Code: |
#include <16F1459.h>
#device *=16
#fuses INTRC_IO,NOPROTECT,MCLR,PUT,NOWDT // CLKOUT -> Enable clk/4 out on PIN_A4
#use delay(int=16MHz, clock=32MHz)
#USE RS232(DEBUGGER,rcv=PIN_B6,xmit=PIN_B6,stream=STREAM_MONITOR)
#zero_ram
void main(void){
unsigned int32 Vol, Prc, Sum;
delay_ms(100); //StartUp Delay.
setup_adc(ADC_OFF); //Stop ADC.
setup_adc_ports(NO_ANALOGS); //Disable Adc-channels.
setup_comparator(NC_NC_NC_NC);//Disable Comparator module.
printf("\n\rTarget 16F1459 Start.\n\r");
Vol = 1234567;
Prc = 12345;
Sum = ((unsigned int32)Vol*Prc)/100; // check Sum overflow?
printf("\r\nSum=%lu\r\n", Sum);
for(;;){
//
}
} |
How long take this calc. "Sum = ((unsigned int32)Vol*Prc)/100;" and can be optimized?
How to check with lowlevel asm flags (some carry flag)?
Quote: |
Easy. Check to see if the result (a^2 + b^2) is less than either a^2 or b^2. If it is, there was an overflow. It's not a valid test for all combinations of a & b, but it's probably sufficient most of the time. |
This check is not 100% ? If a^2 or b^2 overflow this compare will not be valid? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19590
|
|
Posted: Tue Apr 14, 2020 12:38 pm |
|
|
Code: |
#byte STATUS=getenv("SFR:STATUS")
#bit CARRY=STATUS.0
|
The carry bit is then available for you to test. |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1358
|
|
Posted: Tue Apr 14, 2020 1:14 pm |
|
|
Ttelmah wrote: | Code: |
#byte STATUS=getenv("SFR:STATUS")
#bit CARRY=STATUS.0
|
The carry bit is then available for you to test. |
If the mnemonic is unique, you can also just do the bit variable using getenv():
Code: |
#bit CARRY=getenv("BIT:C")
|
|
|
|
kmp84
Joined: 02 Feb 2010 Posts: 363
|
|
Posted: Tue Apr 14, 2020 2:15 pm |
|
|
Code: |
#byte STATUS=getenv("SFR:STATUS")
#bit CARRY=STATUS.0
#bit CARRY=getenv("BIT:C") |
With both declaration CARRY bit doesn't change after mul. overflow.
Code: |
Sum = (unsigned int32)Vol*Prc;
printf("\r\nSum=%lu, Carry:%u\r\n", Sum, CARRY); |
Compiler ver.5.092. |
|
|
gaugeguy
Joined: 05 Apr 2011 Posts: 306
|
|
Posted: Tue Apr 14, 2020 2:53 pm |
|
|
The carry bit is going to be corrupted by the math in the printf function. You need to preserve the status of the carry bit just after the multiply by copying its state into another variable. |
|
|
kmp84
Joined: 02 Feb 2010 Posts: 363
|
|
Posted: Tue Apr 14, 2020 3:07 pm |
|
|
Quote: |
The carry bit is going to be corrupted by the math in the printf function. You need to preserve the status of the carry bit just after the multiply by copying its state into another variable. |
It's not the problem. In debug mode also doesn't change. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19590
|
|
Posted: Wed Apr 15, 2020 1:57 am |
|
|
Key word 'DEBUG'.
If you look at the older thread about this, with the link I gave in my first
reply, you will see that he found the debugger did not correctly update
the status bits, but that they were updating.
Code: |
int1 carry_copy;
Sum = (unsigned int32)Vol*Prc;
carry_copy=CARRY;
printf("\r\nSum=%lu, Carry:%u\r\n", Sum, carry_copy);
|
As a comment too, you don't show the declarations of Vol, and Prc,
but if Prc is not int32, then how can an overflow occur?. Int32
arithmetic won't overflow multiplying any smaller type. If you are
multiplying int16's and want to verify the result will fit into an int16,
you need to use int16 arithmetic, or int32 arithmetic, store the result
into an int32, and then test the result against INT16_MAX from
stdint.h.
You say in your original post that you are using unsigned int32
variables, but in your post here you show a variable being cast up
to be an unsigned int32. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19590
|
|
Posted: Wed Apr 15, 2020 3:54 am |
|
|
OK.
Update on this.
I went back to a really old compiler, and tried a test on a basic PIC18.
On this the carry flag does get set (V4 compiler).
However on the PIC16 here, and on the current compilers, it doesn't.
On the PIC16 here it is permanently clear. On the PIC18, it is permanently
set even if there isn't an overflow.
The way to get to this is to access the contents of @MUL3232.@SCRATCH1
However not sure of an easy way to find this.
Wrote a basic program by using the symbol file to get the address of this
which on this code was address 0x5B
Code: |
#DEFINE OVERFLOW 0x5B //@MUL3232.@SCRATCH1
void main()
{
unsigned int32 Vol, Prc, Sum;
unsigned int16 carry_copy;
Vol = 1234567;
Prc = 12345;
sprintf(output, "\n\rTarget 16F1459 Start.\n\r");
while(TRUE)
{
for (Prc=3000;Prc<15000;Prc+=100)
{
Sum = Vol*Prc;
carry_copy=*(int16*)OVERFLOW;
carry_copy=carry_copy!=0;
sprintf(output, "\r\nSum=%lu, Carry:%lu\r\n", Sum, carry_copy);
delay_cycles(1);
}
}
}
|
This correctly sees 'carry_copy' go to 1, when the maths overflows on
the fifth loop. I don't know if there is an easy way to make a variable
access the scratch variable without having to look it up in the symbol
file. Maybe getenv will allow access to the scratch variables?.
I know it will tell you where the scratch area 'is', but not if there is
any way of finding a specific variable... |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9270 Location: Greensville,Ontario
|
|
Posted: Wed Apr 15, 2020 5:23 am |
|
|
hmm..I've been pondering this and ...
if you check to see if BOTH variables are > than a 'magic' value, then you will have an overflow.
Using unsigned 8 bit variables A, B, RESULT
If A and B are both => 16, an overflow will occour for RESULT.
In this case 16 is the 'magic' value, accually the square root of 256.
Potentially it should be faster being done BEFORE the A X B operation ?
This looks good in my mind...hopefully someone smarter than me can check it out....
Jay |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1358
|
|
Posted: Wed Apr 15, 2020 6:38 am |
|
|
temtronic wrote: | hmm..I've been pondering this and ...
if you check to see if BOTH variables are > than a 'magic' value, then you will have an overflow.
Using unsigned 8 bit variables A, B, RESULT
If A and B are both => 16, an overflow will occour for RESULT.
In this case 16 is the 'magic' value, accually the square root of 256.
Potentially it should be faster being done BEFORE the A X B operation ?
This looks good in my mind...hopefully someone smarter than me can check it out....
Jay |
In this vein, I don't think you need a magic value. Just check and see if the result of the multiplication is LESS than both of the operands. If so, the multiplication wrapped around (overflowed).
Does that seem viable/plausible?
Last edited by jeremiah on Wed Apr 15, 2020 8:13 am; edited 2 times in total |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19590
|
|
Posted: Wed Apr 15, 2020 7:29 am |
|
|
Yes,
The magic value approach has issues. Think about the situation where
one value (for the 8bit example), is 254, while the other is just 2. Both
numbers are not greater than 16, yet the value will definitely overflow....
The test that would work, would be to work out which of the initial values
was the largest, then if the result is less than this, an overflow has taken
place. This is Jeremiah's suggestion. The only situation that also has to
be tested for is one of the multiplicands being zero. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9270 Location: Greensville,Ontario
|
|
Posted: Wed Apr 15, 2020 8:29 am |
|
|
Well I knew thinking without coffee is a bad idea....
I was just trying to save a lot of time doing the multiply
so much for a clever shortcut, but I'm glad others figured it out.... |
|
|
kmp84
Joined: 02 Feb 2010 Posts: 363
|
|
Posted: Wed Apr 15, 2020 9:02 am |
|
|
Thanks mr. Ttelmah,
You 'save' my future project
For me the easy way was to check STATUS overflow bit. I don't know why CCS 'destroy' standard working features. May be in v.6.xxx will come back .
Best Wishes. |
|
|
|