Why are values over 100 become negative? - printf

I'm working on a deserializer in C++. I get a stream of data and I am transferring this to a char array. At the moment, everything is working perfectly except when the value is over 100, the value I get returned becomes a negative value. For example 241 becomes -15 but values below what it seems to be 100 stay the same.
Here is the code I am running
char streamBuffer[1024]; //where the stream data is held
/**code in between that transfer data stream to streamBuffer[]**/
char printBuffer[10];
for(int i = 0; i < 10 ; i++){
sprintf(printBuffer, "streamData = %ld",streamBuffer[i]);
PrintData(printBuffer); //prints the value
}
For example, my stream data could look like 1,3,5,10,241,etc.
When I get to the printData function, it gives me the correct value for any value below 100 it seems.
I've used
sprintf(printBuffer, "streamData = %lld",streamBuffer[i]);
or
sprintf(printBuffer, "streamData = %d",streamBuffer[i]);
but I am still not getting the right values.
So my output will look like this.
StreamData: 1
StreamData: 3
StreamData: 5
StreamData: 10
StreamData: -15

Solution was to change char streamBuffer[1024] to unsigned char streamBuffer[1024] and change %ld to %u in the sprintf statement. Now values over 100 remain the same.

Related

How to process mainframe numbers where "{" is the last character

I have a one mainframe file data like as below
000000720000{
I need to parse the data and load into a hive table like below
72000
the above field is income column and "{" sign which denotes +ve amount
datatype used while creating table income decimal(11,2)
in layout.cob copybook using INCOME PIC S9(11)V99
could someone help?
The number you want is 7200000 which would be 72000.00.
The conversion you are looking for is:
Positive numbers
{ = 0
A = 1
B = 2
C = 3
D = 4
E = 5
F = 6
G = 7
H = 8
I = 9
Negative numbers (this makes the whole value negative)
} = 0
J = 1
K = 2
L = 3
M = 4
N = 5
O = 6
P = 7
Q = 8
R = 9
Let's explain why.
Based on your question the issue you are having is when packed decimal data is unpacked UNPK into character data. Basically, the PIC S9(11)V2 actually takes up 7 bytes of storage and looks like the picture below.
You'll see three lines. The top is the character representation (missing in the first picture because the hex values do not map to displayable characters) and the lines below are the hexadecimal values. Most significant digit on top and least below.
Note that in the rightmost byte the sign is stored as C which is positive, to represent a negative value you would see a D.
When it is converted to character data it will look like this
Notice the C0 which is a consequence of the unpacking to preserve the sign. Be aware that this display is on z/OS which is EBCDIC. If the file has been transferred and converted to another code-page you will see the correct character but the hex values will be different.
Here are all the combinations you will likely see for positive numbers
and here for negative numbers
To make your life easy, if you see one of the first set of characters then you can replace it with the corresponding number. If you see something from the second set then it is a negative number.

Reduce Complexity of This Formula?

I have a question about optimizing a formula I've been using in Google Sheets:
=ARRAYFORMULA(
IF(
IFERROR(
MATCH($B2 & A2, ($B$1:B1) & ($A$1:A2), 0),
0
) = 0,
1,
0))
The formula works by counting all the unique values in column A (ID) given that it appears in the date range of column B (Date), to give an output in column C (Count).
Notice how the count values are only 0 and 1, and will only show a 1 if it is the ID's first appearance in the date range.
Example data below.
ID Date Count
138 Oct-13 1
138 Oct-13 0
29 Oct-13 1
29 Nov-13 1
138 Nov-13 1
138 Nov-13 0
The issue is once I get over 10000 lines to parse, the formula grinds to a slow pace, and takes upwards of an hour to finish computing. I'm wondering if anyone has a suggestion on how to optimize this formula so I don't need to have it running for so long.
Thanks,
I've been playing around with some formulas, and I think this one works better, but is still becoming quite slow after 10000 lines.
=IF(COUNTIF((FILTER($A$1:$A2, $B$1:$B2 = $B2)),$A2) = 1, 1, 0)
Edit
Here is an additional formula posted on the Google Product Forum which only has to be put in one cell, and autofills down. This is the best answer I've found so far.
=ArrayFormula(IF(LEN(A2:A),--(MATCH(A2:A&B2:B,A2:A&B2:B,0)=ROW(A2:A)-1),))
I wasn't able to find a formula-only solution that I could say outperforms what you have. I did, however, come up with a custom function that runs in linear time, so it ought to perform well. I'd be curious to know how it compares to your final solution.
/**
* Returns 1 for rows in the given range that have not yet occurred in the range,
* or 0 otherwise.
*
* #param {A2:B8} range A range of cells
* #param {2} key_col Relative position of a column to key by, e.g. the sort
* column (optional; may improve performance)
* #return 1 if the values in the row have not yet occurred in the range;
* otherwise 0.
* #customfunction
*/
function COUNT_FIRST_OF_GROUP(range, key_col) {
if (!Array.isArray(range)) {
return 1;
}
const grouped = {};
key_col = typeof key_col === 'undefined' ? 0 : key_col - 1; // convert from 1-based to 0-based
return range.map(function(rowCells) {
const group = groupFor_(grouped, rowCells, key_col);
const rowStr = JSON.stringify(rowCells); // a bit of a hack to identify unique rows, but probably a good compromise
if (rowStr in group) {
return 0;
} else {
group[rowStr] = true;
return 1;
}
});
}
/** #private */
function groupFor_(grouped, row, key_col) {
if (key_col < 0) {
return grouped; // no key column; use one big group for all rows
}
const key = JSON.stringify(row[key_col]);
if (!(key in grouped)) {
grouped[key] = {};
}
return grouped[key];
}
To use it, in Google Sheets go to Tools > Script editor..., paste it into the editor, and click Save. Then, in your spreadsheet, use the function like so:
=COUNT_FIRST_OF_GROUP(A2:B99, 2)
It will autofill for all rows in the range. You can see it in action here.
If certain assumptions are fulfilled, Like, 1. Same ID numbers always occur together(If not, maybe you could SORT them by ID first and then date later), then,
=ARRAYFORMULA(1*(A2:A10000&B2:B10000<>A1:A9999&B1:B9999))
If dates are recognised, I think you could use + instead of & . Again, Various assumptions were made here and there.

What is the most elegant way to pick a random value from a set defined in NS_OPTION in objective-c?

I have an NS_OPTION that I'm defining as such :
typedef NS_OPTIONS(NSInteger, PermittedSize) {
SmallSize = 1 << 0,
MediumSize = 1 << 1,
LargeSize = 1 << 2
};
And later I set the values I need :
PermittedSize size = SmallSize | MediumSize;
I'm using it to randomly generate an various objects of small and medium sizes(duh) for a particular level of a game.
What is the best way to go about selecting which size of an object to generate? Meaning, I'd like to choose randomly for each object I'm generating whether it will be one of the 2 options allowed (small and medium in this case). Normally I would use an arc4random function with the range of numbers I need - but in this case, how can it be done with bits? (and then mapped back to the values of the PermittedSize type?
Use the result from arc4random to determine the amount of bit shifting you want to do. Something like this:
int bitShiftAmount = arc4random_uniform(numberOfPermittedSizes);
PermittedSize size = 1 << bitShiftAmount;
You are still working with integers. SmallSize is 1. MediumSize is 2. And LargeSize is 4.
So pick a random number from 1 to 3. 1 is small, 2 is medium, 3 is both.
Once you have a random number, assign it.
NSInteger val = arc4random_uniform(3) + 1; // give 1-3
PermittedSize size = (PermittedSize)val;

How to convert hex to binary?

For Objective-C:
Hi everyone, I'm trying to convert a hex input into binary. For example, someone enters in :
A55
I want that to convert to
101001010101
I've tried looking through past posts and none seem to be working for me. Any help would be greatly appreciated.
Use a lookup table: there are only 16 possible characters in a HEX representation, each corresponding to a four-character binary code group. Go through the HEX character-by-character, obtain a lookup, and put it in the resultant NSString.
Here is a copy of the lookup table for you.
0 0000
1 0001
2 0010
3 0011
4 0100
5 0101
6 0110
7 0111
8 1000
9 1001
A 1010
B 1011
C 1100
D 1101
E 1110
F 1111
There are multiple options as to how to do lookups. The simplest way would be making a 128-element array, and placing NSStrings at the elements corresponding to codes of the characters (i.e. at positions '0', '1', ..., 'E', 'F', with single quotes; these are very important).
I believe there is a built-in function for this. If not, you should at least be able to go hex->dec then dec->bin
You can write the conversion from scratch if you know the number of characters, bin to hex is common enough algorithmically.
A mathematical look at the algorithms
SO Answers in C/C++ Another
Base 10 to base n in Objective C
C Hex->Bin
Build a lookup table (an array where you can supply a value between 0 and 15 to get the binary for that hex digit):
char *hex_to_bin[] = {
"0000", "0001", "0010", "0011",
/* ... */
"1100", "1101", "1110", "1111"
};
There should be 16 elements in that table. The conversion process for multiple digits is to handle one digit at a time, appending the results onto the end of your result storage.
Use getchar() to read a char:
int c = getchar();
if (c < 0) { puts("Error: Invalid input or premature closure."); }
Use strchr() to determine which array index to retrieve:
char *digits = "00112233445566778899AaBbCcDdEeFf";
size_t digit = (strchr(digits, c) - digits) / 2;
Look up the corresponding binary values for digit:
printf("%s", hex_to_bin[digit]); // You'll want to use strcat here.

combine/merge two bytes into one...?

I working with serial frames. I'm receiving a 16-bit value as two separate 8-bit values. How can I merge buffer[0] with buffer[1]? I don't want 0b01+0b10 = 12 (base 10). I want it to equal 258.
How can I accomplish this?
uint16_t value = (highByte << 8) | lowByte ;