Packed Number Simplified!
To write the first blog took me some time though there are few topics in my mind which I think I should blog. To write a blog with the right contents and presenting in a way which is very helpful for others is a challenge and hats off to al the bloggers for their efforts. I have been a constant follower of scn blogs and many such blogs has helped me a lot. So this is my first humble attempt to share something which I feel would help anyone who come across similar issue.
The topic is about packed number. Recently I came across an issue with one of our customers where they having issues storing large amount value to a packed decimal field. It was throwing overflow exception . To solve this issue I tried searching to get to know how packed decimals behave I couldn’t get enough details anywhere about the exact behavior of packed decimals and i had spend some time to write a test program to understand the right behavior of packed decimals.
Customer was having a custom domain of data type dec length 16 and decimal 9 .Based on the various documentations on packed number our assumption was that we have created a packed number with maximum length possible which is length 16 .
The amount value we were trying to store is 100000000.00. 9 digits before the decimal and 2 digits after the decimal .We were getting an overflow exception .I could see from the amount value if i reduce the number of digits before the decimal by one the overflow exception doesn’t happen ( 8 digits before the decimal and 9 digits after the decimal ) . This made me wonder what’s the length all about and how it works in case of packed decimal . I spend some time debugging the issue.
Below is how it appeared in the debugger .
What I understand is though I have declared my domain is of length 16 and dec 9 ,internally system converts into a packed decimal of length 9 and
dec 9 .P(9) DECIMAL 9.Now I had to understand what’s this length stands for ,what does it mean by length 9 in case of packed decimal.
Predefined Numeric Types is explained here ABAP Keyword Documentation
Based on definitions about packed decimal length 9 means 9 bytes and 2 digits forms 1 byte and so the actual length is 18 digits which includes one space for +/- sign. So in this case a domain declared with the length 16 and decimal 9 is converted by the system as a packed decimal of length 9 and decimal 9 which means a total of 18 digits including 9 decimal and 8 digits before the decimal and one space for the sign . Now I understood the reason why the amount 100000000.00 was not accepted by the variable ,instead 10000000.00 was accepted .
Overview of All Predefined Dictionary Types is explained here ABAP Keyword Documentation
Below is the test program to understand more about packed decimals.
REPORT ZTEST_PROGRAM
*Data Declarations
data lv_char(50) value ‘9.999999999’.
data: lv_p TYPE p LENGTH 16 DECIMALS 9.
data: lv_num type i value 1.
data: lv_dec type i value 9.
write:/ ‘Keeping Decimal place constant as 9’.
DO 25 TIMES.
lv_num = lv_num + 1.
CONCATENATE ‘9’ lv_char into lv_char.
TRY .
lv_p = lv_char.
CATCH CX_SY_CONVERSION_OVERFLOW .
write:/’overflow’.
ENDTRY.
CHECK lv_p is NOT INITIAL.
write:/ lv_p, lv_num ,’Numbers and’, lv_dec,’ Decimals’.
ENDDO.
uline.
write:/ ‘Keeping Decimal place constant as 9 in the situation’.
CLEAR: lv_num,lv_dec,lv_p,lv_char.
lv_char = ‘9.999999999’.
lv_num = 1. lv_dec = 9.
DO 10 TIMES.
lv_num = lv_num + 1.
CONCATENATE ‘9’ lv_char into lv_char.
TRY .
lv_p2 = lv_char.
CATCH CX_SY_CONVERSION_OVERFLOW .
write:/’overflow’.
ENDTRY.
CHECK lv_p2 is NOT INITIAL.
write:/ lv_p2, lv_num ,’Numbers and’, lv_dec,’ Decimals’.
ENDDO.
uline.
write:/ ‘Keeping Decimal place constant as 3’.
CLEAR: lv_num,lv_dec,lv_p,lv_char.
data: lv_p1 TYPE p LENGTH 9 DECIMALS 3.
lv_char = ‘9.999’.
lv_num = 1.
lv_dec = 3.
DO 20 TIMES. lv_num = lv_num + 1.
CONCATENATE ‘9’ lv_char into lv_char.
TRY .
lv_p1 = lv_char.
CATCH CX_SY_CONVERSION_OVERFLOW .
write:/’overflow’.
ENDTRY.
CHECK lv_p1 is NOT INITIAL.
write:/ lv_p1, lv_num ,’Numbers and’, lv_dec,’ Decimals’.
ENDDO.
If we have to keep the length fixed for the domain( declared length 16 decimal 9 ) , reduce the decimal points to hold more digits before the decimal .Below is a screenshot to show when the overflow will occur for the used domain reducing the decimal is reduced to 3 digits. Below is the output from the above code . This shows 14 Numbers are possible before decimal and 3 numbers after decimal.
So what we have to understand is the length defined in the domain is not the actual length of the packed decimal. if I declare a domain of length 20 and decimal 9 ,in debugger I could see the system converts it to a packed decimal of length 11 and decimal 9.The maximum allowed length of packed decimal is 16 which is 16 bytes .
So to understand maximum value possible, I have increased the local packed decimal variable to 16 and was able to see maximum number possible keeping decimals as 9 was huge number – in the help documentation – a formula is provided as well. For easy understanding below screen shot is given.
So above code also support my understanding of 16*2 = 32 numbers possible in which 1 will be taken by +/- sign – which will be 22+9 = 31.
Hope this blog was useful.
You can also read more about predefined numeric type in in help.sap.com
What I like about this blog is that it is
a) From a personal view point and
b) Explains the process that was gone through to figure things out
Well done.
Hi Mathew,
Thanks for your valuable feedback.
Thanks and Regards
Neeta
May be you should add the ABAP documentation to your post - Predefined Numeric Types - ABAP Keyword Documentation
Explained here - Overview of All Predefined Dictionary Types - ABAP Keyword Documentation
Hi Suhas ,
Thanks for your valuable feedback.I will update my blog accordingly.
Thanks and Regards
Neeta
Good work, Neeta! The blog post solves a problem, is illustrated with screenshots and has the detailed code to help consultants.
Neeta,Thanks.
Now, we have one blog with person exp which we can refer to when we need.
But,did you find any explaination on what basis SAP considers the packed decimals
In the below example :-
For lv_p1 it considered P(9) Decimals 2.
For lv_p2 it considered P(7) Decimals 2.
My understanding is
data type CURR, Length 16, Decimal Places 2, Output length 21.
Can hold a max of 16 characters (including dot with 2 values after that, for saving in Database)
Output length 21 is to accomodate the comma separators and +/- at the level of table display.
P(9) Decimals 2 – indicates 9 bytes ie 18 characters.
data type CURR Length 13 Decimal Places 2 Output length 16.
Can hold a max of 13 characters (including dot with 2 values after that, for saving in Database)
Output length 16 is to accomodate the comma separators and +/- the level of table display.
P(7) Decimals 2 – indicates 7 bytes ie 14 characters.
Thanks,
K.Kiran.
useful blog . Thank you so much
Nice Blog. Here are few more details, hope it helps.
1. Packed numbers are used to do fixed point arithmetic in ABAP. (that why fixed point arithmetic attribute should be set while using P) . On a high level, Idea behind fixed point arithmetic is, to multiple a number by (base ^ d ), so that number is left shifted by d digits ( d depends upon how many decimal places you want) and can be easily stored knowing d. Which can eventually be converted back easily by right shifting by d times to get actual number.
A packed byte is packed byte coded decimal (aka packed BCD) , in 1 byte, half byte i.e. 4 bit is enough to encode 1 decimal digit. Thus each packed byte can be used to encode two numbers ( though depending upon CPU word size it can have more than two digits in 1 word )
In ABAP P data type is packed byte with total number of packed byte as n and Decimal digits . i.e. so it would mean 2n digits. Last packed byte uses 1 byte for number and other for sign, Thus you get 2n-1 digits to encode a number. Out of those 2n-1 digits, d digits are reserved for decimal places so remaining ( 2n - 1 - d ) are used for integer part . In ABAP d <=14 and of course n >= d.
In your case length for type P is16 which means total digits are 31 ( 2n-1) . Since you have 9 decimal places so remaining 31-9 = 22 digits used for integer part.
Overflow: Overflow occurs if you either assign a number with more digits in integer part than declared limit or total number of digits is more than declared part. In type P fractional part always padded with 0. So even if you have used less number of digits in fractional part it would still consume full decimal length as per declaration.
So in your case ( P Length 9 Decimal 9 ) if assigned values is 999999999.9 or 999999999.999999999 both will overflow. However if 9999999.9999999999 (it won't overflow but you will get a different number (in this case it's most probably 1 right shifted in corresponding binary or depends upon BCD encoding used in ABAP ).
2. Type DEC ( in data dictionary predefined types): You could only enter 9 digits since you used data dictionary predefined type DEC in which length actually mean number of digits and not packed bytes. DEC is then translated as corresponding type P in your program.
Since you used 16 length in your domain which is a even number of places so it will need 16/2 packed byte and 1 more for sign i.e. total of 8 + 1 = 9 packed bytes (thus half byte wasted for each so an odd number length should be used while using DEC ).
Thus in your case it was DEC length 16 decimal 9 would have corresponding packed representation as P Length 9 Decimal 9. which gives you 17 - 9 = 8 before and 9 places after decimal.
Regards,
Naveen Trivedi
Hope this helps.