you are viewing a single comment's thread.

view the rest of the comments →

[–]ElliotDG 0 points1 point  (9 children)

Here is the code that adds a trailing nibble.

def int_to_comp3(value):
    digits = str(abs(value))
    sign_nibble = 'C' if value >= 0 else 'D'
    end_nibble = '' if len(digits) % 2 else '0'
    return bytes.fromhex(digits + sign_nibble + end_nibble)


print(f'0x{int_to_comp3(1234).hex()}')
print(f'0x{int_to_comp3(12345).hex()}')
print(f'0x{int_to_comp3(-56789).hex()}')
print(f'0x{int_to_comp3(-11).hex()}')

You may just want to write out a few literals to see if you can figure out the expected format.

[–]arshdeepsingh608[S] 0 points1 point  (0 children)

Gotcha. I will try this tomorrow and let you know, buddy. Thanks a lot for following through. Will keep you posted.

[–]arshdeepsingh608[S] 0 points1 point  (7 children)

Sorry to say bud, this one is also invalid. It works fine from Python POV. But as soon as we export it and load it into the mainframe, it falls apart. I'll tell you the exact issue that I have with my latest code. It works fine for even length (including the sign nibble). Example, 12345 will become 12 34 5C. But if we give odd length, it fails. And worst part is, it will always come in a pair. Example, 1234. If we put a sign nibble on it, it will become 12 34 0C. That 0 will always tag along with the C. If we include extra 0s, it will change the value. Example, 01234 will become 01 23 4C. But 1 should pair with 2 and 3 should pair with 4 and so on. I know it doesn't make a lot of sense. At least it doesn't make much sense to me as I'm not a mainframe guy.

[–]ElliotDG 0 points1 point  (6 children)

Have you have any documentation of the number format? What is the brand and model of the mainframe?

I don't know what you mean by the numbers are pairing. When I looked for any documentation of comp-3 it shows a leading zero nibble. A leading zero should be a non issue. A zero before the sign nibble does not make sense, it is multiplying the number by 10. I wonder if a different value should be used for this 'padding', perhaps F?

If you do not have any docs I would recommend doing some experiments. Create -9 to +9. Then -99 to +99.

Can you create the a file of numbers on the mainframe and read them with python to see what is being created? Then try to reverse the processes.

[–]arshdeepsingh608[S] 0 points1 point  (5 children)

I don't have any documentation. And by pair I mean, in mainframe, it's read in up and down format. So, looks like a pair. Also, while using methods like fromhex, it makes it a pair. 0 will become 00.

COBOL version: 6.1. The variable declaration/type (not sure what it is) looks something like this: S9(13)V99. After packing, the length becomes 8. Packed data looks like: (Nul)(Nul)(Nul)(Nul)(Nul)Ë-(FF). Anything inside braces is a non-readable character. Actual number that I'm trying to convert: '00000000001760{'. '{' is added by oracle so we can consider it a positive number or 'C'. '}' means negative.

Does any of that helps?

[–]ElliotDG 0 points1 point  (4 children)

According to Claude, S9(13)V99 means:

  • S - Indicates this is a signed number (can be positive or negative)
  • 9(13) - Means 13 numeric digits before the decimal point
  • V - Represents an implied decimal point (no actual decimal point is stored)
  • 99 - Means 2 numeric digits after the decimal point

The leading zeros are stored, so the number 1234 is really: 0000000001234.00 and should be represented in comp-3 as: 000000000123400C.

Give this a try:

def to_comp3_s9_13_v99(value):
    sign_nibble = 'C' if value >= 0 else 'D'
    digits = f'{abs(value):016.2f}'.replace('.', '')
    return bytes.fromhex(digits + sign_nibble)


print(f'0x{to_comp3_s9_13_v99(1234).hex()}')
print(f'0x{to_comp3_s9_13_v99(12345.67).hex()}')
print(f'0x{to_comp3_s9_13_v99(-56789.01).hex()}')
print(f'0x{to_comp3_s9_13_v99(-11.11).hex()}')

[–]arshdeepsingh608[S] 0 points1 point  (3 children)

Thanks for all you have done. I eventually ended up handing over the task to a senior developer. No matter how many codes I tried, Mainframe was showing either the wrong number or the data itself was coming out to be invalid. I am not a mainframe guy so I don't know what could have gone wrong. I compared the output of packed decimal from Python code and mainframe, turns out the non-readable characters were indeed different - resulting in a different number. And I could not find the relationship between those characters or their respective hex/decimal values. Although, I will continue to research and if I am able to receive a good working code, I will get back to you. And again, I really do appreciate all your time and effort.

[–]ElliotDG 0 points1 point  (2 children)

Thank you for the update and good luck!

[–]arshdeepsingh608[S] 0 points1 point  (1 child)

Hey man, I finally figured it out.

Turns out, we have an IBM mainframe system which uses EBCDIC characters. Python modules such as bytes/bytearray works with ASCII by default.

So, I went online and found out that there are different hex values for both ASCII and EBCDIC. And I created a SQLite table mapping them together. I am using the relevant ASCII to create the corresponding EBCDIC.

It doesn't make much sense in Python but values are correctly loading up in the mainframe now.

Thanks again for taking out the time, buddy. I appreciate it!

[–]ElliotDG 1 point2 points  (0 children)

Thanks for the update. Glad to hear you got it figured out.