Python struct not accepting 0xf031 as unsigned short - python-3.x

So I'm trying to implement a serial line data protocol. One of the commands has hex value 0xf031 (61489 in integer) .
When I try to enter it in as a unsigned short value in a struct I get this as an output:
d1= 61489
d2 = 24
pack('<HH', d1, d2)
>> b'1\xf0\x18\x00'
I expect
b'\x31\xf0\x18\x00'
With some trail and error I found out that the highest value it accepts is 61448
d1= 61448
d2 = 24
print(pack('<HH', d1, d2))
>> b'\x08\xf0\x18\x00'
Have anyone any tips or tricks. Even If i split the two bytes and enter them as single bytes using B (unsigned char) i get the same result.
d1= hex(61489)
d2 = 24
#print(d1)
d1_1 = d1[2:4]
d1_2 = d1[4:]
print(pack('<BBH', int(d1_1, base=16), int(d1_2,base = 16), d2))
>> b'\xf01\x18\x00'
And again the value 61448 gives correct bytes.
Just to show what 61449 gives me
d1= hex(61449)
d2 = 24
#print(d1)
d1_1 = d1[2:4]
d1_2 = d1[4:]
print(pack('<BBH', int(d1_1, base=16), int(d1_2,base = 16), d2))
>> b'\xf0\t\x18\x00'
Im using Jupyter-Lab in pipenv. python 3.8.7

You're seeing what you should be seeing. The 1 in the b-string isn't the value 1, it's the ASCII character "1" (0x31). b-strings will represent as printable characters when possible.
You can see if you convert it back that the original value is still there (in decimal):
>>> unpack('<H', pack('<H', 0xf031))
(61489,)

Related

Splitting numbers into smaller groups

I believe this question is leaning more towards developing the logic than implementation.
I have a 6 digit int value which I need to split into three, three digit numbers.
This is a trivial task but I cannot use any indexing or slicing operations.
Input -
rgb1 = 220020060
rgb2 = 189252201
My expected output is of the form
r1 , g1, b1 = 220, 020, 060
r2, g2, b2 = 189, 252, 201
I have tried using divmod() but unsure of how to get the middle set of values if it is of the form 0x0 where x is any single digit integer.
For example:
r, rest = divmod(rgb1,10**6)
r = 220, rest = 20060
But I am unsure as to how to proceed with extracting further numbers.
What I would do is convert the number to string if 0xx cases exists, as 'int' cannot display leading zeros.
My code:
def splitter(num):
r1, rest=divmod(num,10**6)
if len(str(r1)) !=3:
r1=str(r1)
r1=r1.zfill(3)
if len(str(rest)) !=6:
rest=str(rest)
rest=rest.zfill(6)
g1,rest=divmod(int(rest),10**3)
if len(str(g1)) !=3:
g1=str(g1)
g1=g1.zfill(3)
if len(str(rest)) !=3:
rest=str(rest)
rest=rest.zfill(3)
b1=rest
return r1,g1,b1
Output:
>>> splitter(220020060)
(220, '020', '060')
You can edit the code to display the output in the format you need!

Find strings from an cell array and create a new cell array

I want to find the strings from an cell array (m x n) and add those identified strings in new cell array (m x n), by using matlab, for example:
Human(i,1)={0
1
34
eyes_two
55
33
ears_two
nose_one
mouth_one
631
49
Tounge_one}
I want to remove the numbers and have just strings
New_Human(i,1)={eyes_two
ears_two
nose_one
mouth_one
tounge_one}
Based on your comment it sounds like all your data is being stored as strings. In that case you can use the following method to remove all strings which represent a valid number.
H = {'0'; '1'; '34'; 'eyes_two'; '55'; '33'; 'ears_two'; 'nose_one'; 'mouth_one'; '631'; '49'; 'Tounge_one'};
idx = cellfun(#(x)isnan(str2double(x)), H);
Hstr = H(idx)
Output
Hstr =
'eyes_two'
'ears_two'
'nose_one'
'mouth_one'
'Tounge_one'
The code determines which strings do not represent valid numeric values. This is accomplished by checking if the str2double function returns a NaN result on each string. If you want to understand more about how this works I suggest you read the documentation on cellfun.

Why do these idneitcal QB calculations produce slightly different values?

So, I'm trying to port some very old and venerable engineering analysis QBasic 4.5 code into C. I'm trying to match results exactly, and I find that I can't quite understand how QB does its math.
For example, these two lines
DIM a AS SINGLE
DIM d2 AS SINGLE
DIM e2 AS SINGLE
a = 32.174
d2 = 1! / (2! * 32.174 * 144!)
e2 = 1! / (2! * a! * 144!)
d2 becomes 1.07920125E-4 (floating point 0x38e2532d)
e2 becomes 1.0792013E-4 (floating point 0x38e2532e)
which are ever so slightly different. Can anyone help me understand why? Thanks very much.
I'm getting the same output for both d2 and e2, even in terms of the raw byte representation of the values. Here's some annotated output:
# Calculation results
d2: 38 E2 53 2E
e2: 38 E2 53 2E
1.079201E-04 = 1.079201E-04
# Result of changing the last byte (some mantissa bits) to alter the value,
# proving they're not equal
d2: 38 E2 53 2F
e2: 38 E2 53 2E
1.079201E-04 <> 1.079201E-04
# Result above may just be luck. This result alters the first byte
# (some exponent bits) to prove that the intended bits were altered.
d2: 39 E2 53 2E
e2: 38 E2 53 2E
4.316805E-04 <> 1.079201E-04
Code:
DIM a AS SINGLE
DIM SHARED d2 AS SINGLE
DIM SHARED e2 AS SINGLE
a = 32.174
d2 = 1! / (2! * 32.174 * 144!)
e2 = 1! / (2! * a! * 144!)
' Print the hex representation of the bytes
' and show they're initially equal.
CALL printHex
PRINT
' Change the last byte of the mantissa by 1 bit.
' Show that doing this makes the two values unequal.
DEF SEG = VARSEG(d2)
POKE VARPTR(d2), PEEK(VARPTR(d2)) + 1
DEF SEG
CALL printHex
PRINT
' Show that the correct byte was poked by reverting mantissa change and
' altering exponent.
DEF SEG = VARSEG(d2)
POKE VARPTR(d2), PEEK(VARPTR(d2)) - 1
POKE VARPTR(d2) + 3, PEEK(VARPTR(d2) + 3) + 1
DEF SEG
CALL printHex
SUB printHex
'SHARED variables used:
' d2, e2
DIM d2h AS STRING * 8, e2h AS STRING * 8
' Get bytes of d2 and e2, storing them as hexadecimal values
' in d2h and e2h.
DEF SEG = VARSEG(d2)
MID$(d2h, 1) = hexByte$(PEEK(VARPTR(d2) + 3))
MID$(d2h, 3) = hexByte$(PEEK(VARPTR(d2) + 2))
MID$(d2h, 5) = hexByte$(PEEK(VARPTR(d2) + 1))
MID$(d2h, 7) = hexByte$(PEEK(VARPTR(d2)))
DEF SEG = VARSEG(e2)
MID$(e2h, 1) = hexByte$(PEEK(VARPTR(e2) + 3))
MID$(e2h, 3) = hexByte$(PEEK(VARPTR(e2) + 2))
MID$(e2h, 5) = hexByte$(PEEK(VARPTR(e2) + 1))
MID$(e2h, 7) = hexByte$(PEEK(VARPTR(e2)))
DEF SEG
' Print the bytes, separating them using spaces.
PRINT "d2: "; MID$(d2h, 1, 2); " "; MID$(d2h, 3, 2); " ";
PRINT MID$(d2h, 5, 2); " "; MID$(d2h, 7, 2)
PRINT "e2: "; MID$(e2h, 1, 2); " "; MID$(e2h, 3, 2); " ";
PRINT MID$(e2h, 5, 2); " "; MID$(e2h, 7, 2)
' Print whether d2 is equal to e2.
IF d2 = e2 THEN
PRINT d2; "= "; e2
ELSE
PRINT d2; "<>"; e2
END IF
END SUB
FUNCTION hexByte$ (b%)
' Error 5 is "Illegal function call".
' This can only happen if b% is outside the range 0..255.
IF b% < 0 OR b% > 255 THEN ERROR 5
' MID$("0" + HEX$(15), 2 + (-1)) => MID$("0F", 1) => "0F"
' MID$("0" + HEX$(16), 2 + ( 0)) => MID$("010", 2) => "10"
hexByte$ = MID$("0" + HEX$(b%), 2 + (b% < 16))
END FUNCTION
EDIT
As #BlackJack explained in the comments, the effects you're noticing appear to occur when the file is compiled. Since that was the clue given, I used the CodeView debugger in DOSBox, and here's the abridged result:
5: a = 32.174
057D:0030 C70636002DB2 MOV Word Ptr [0036],B22D
057D:0036 C70638000042 MOV Word Ptr [0038],4200
6: d2 = 1! / (2! * 32.174 * 144!)
057D:003C C7063A002D53 MOV Word Ptr [003A],532D
057D:0042 C7063C00E238 MOV Word Ptr [003C],38E2
7: e2 = 1! / (2! * a! * 144!)
057D:0048 CD35065000 FLD DWord Ptr [0050]; 00 CB 21 CD
057D:004D CD34363600 FDIV DWord Ptr [0036]; 42 00 B2 2D
057D:0052 CD351E3E00 FSTP DWord Ptr [003E]; e2 = result
057D:0057 CD3D FWAIT
The BASIC Compiler (BC.EXE) reduced the assignment to d2 to a simple assignment of a floating-point constant (i.e. it evaluated the expression itself and optimized your code to that single assignment rather than performing all of the operations you specified). However, the assignment to e2 isn't that simple since it contains a non-constant expression a!.
To combat the problem and attempt to keep as much precision as possible, it changed 1 / (2 * a * 144) to the mathematically equivalent (1 / 288) / a, and the approximate value of 1 / 288 was stored at offset 0x0050, which is why FLD ended up loading that offset. After loading that SINGLE value, it divided it by the value of a (offset 0x0036) and stored the result in e2 (offset 0x003E). You can make the assignment to e2 the same as d2 by using CONST a = 32.174, but you cannot change its value then.
Someone is probably wondering by now why this only happens when compiled and not in the IDE, and I honestly don't know. My best guess is the IDE keeps as many floats on the FP stack as much as it can to retain precision, so instead of using the 32-bit rounded value of a, it uses the existing 80-bit value stored on the FP stack already, if it is still stored there. This way, there's less precision loss since storing the 80-bit value outside of the FP stack requires rounding to the nearest 32-bit or 64-bit value, depending on where you specify to store the value. Of course, if more than 8 values are needed on the FP stack for some reason, one will need to be swapped out to make room for another, and the precision loss will manifest eventually.
#BlackJack also pointed out that the IDE is interpreting the code rather than compiling it with optimizations, which could be the reason that the byte representations are the same when the code is run in the IDE but different in a compiled version. That is, both the computations of d2 and e2 are executed in the exact same way rather than optimizing the calculation of d2 to a single value as BC.EXE does.
In any case, you likely don't notice it in your C code because your modern compiler is a lot smarter and has more memory to work with when it comes to optimizing than BC.EXE, even without the help of modern floating-point technologies like SSE2.
Which QB version are you using? And how are you printing or outputing your variables d2 and e2?
When I try your program in QuickBASIC 4.5 in DOSBox 0.74 I don't get different values, d2 and e2 are the same when I PRINT them.
a = 32.174
d2 = 1.079201E-04
e2 = 1.079201E-04
The exlamation mark operator will typecast it to SINGLE (single precision, 4 bytes), so it's same as AS SINGLE. Maybe the value 32.174 in your line d2 = 1! /.. is being typecast to DOUBLE somehow?

How to compute word scores in Scrabble using MATLAB

I have a homework program I have run into a problem with. We basically have to take a word (such as MATLAB) and have the function give us the correct score value for it using the rules of Scrabble. There are other things involved such as double word and double point values, but what I'm struggling with is converting to ASCII. I need to get my string into ASCII form and then sum up those values. We only know the bare basics of strings and our teacher is pretty useless. I've tried converting the string into numbers, but that's not exactly working out. Any suggestions?
function[score] = scrabble(word, letterPoints)
doubleword = '#';
doubleletter = '!';
doublew = [findstr(word, doubleword)]
trouble = [findstr(word, doubleletter)]
word = char(word)
gameplay = word;
ASCII = double(gameplay)
score = lower(sum(ASCII));
Building on Francis's post, what I would recommend you do is create a lookup array. You can certainly convert each character into its ASCII equivalent, but then what I would do is have an array where the input is the ASCII code of the character you want (with a bit of modification), and the output will be the point value of the character. Once you find this, you can sum over the points to get your final point score.
I'm going to leave out double points, double letters, blank tiles and that whole gamut of fun stuff in Scrabble for now in order to get what you want working. By consulting Wikipedia, this is the point distribution for each letter encountered in Scrabble.
1 point: A, E, I, O, N, R, T, L, S, U
2 points: D, G
3 points: B, C, M, P
4 points: F, H, V, W, Y
5 points: K
8 points: J, X
10 points: Q, Z
What we're going to do is convert your word into lower case to ensure consistency. Now, if you take a look at the letter a, this corresponds to ASCII code 97. You can verify that by using the double function we talked about earlier:
>> double('a')
97
As there are 26 letters in the alphabet, this means that going from a to z should go from 97 to 122. Because MATLAB starts indexing arrays at 1, what we can do is subtract each of our characters by 96 so that we'll be able to figure out the numerical position of these characters from 1 to 26.
Let's start by building our lookup table. First, I'm going to define a whole bunch of strings. Each string denotes the letters that are associated with each point in Scrabble:
string1point = 'aeionrtlsu';
string2point = 'dg';
string3point = 'bcmp';
string4point = 'fhvwy';
string5point = 'k';
string8point = 'jx';
string10point = 'qz';
Now, we can use each of the strings, convert to double, subtract by 96 then assign each of the corresponding locations to the points for each letter. Let's create our lookup table like so:
lookup = zeros(1,26);
lookup(double(string1point) - 96) = 1;
lookup(double(string2point) - 96) = 2;
lookup(double(string3point) - 96) = 3;
lookup(double(string4point) - 96) = 4;
lookup(double(string5point) - 96) = 5;
lookup(double(string8point) - 96) = 8;
lookup(double(string10point) - 96) = 10;
I first create an array of length 26 through the zeros function. I then figure out where each letter goes and assign to each letter their point values.
Now, the last thing you need to do is take a string, take the lower case to be sure, then convert each character into its ASCII equivalent, subtract by 96, then sum up the values. If we are given... say... MATLAB:
stringToConvert = 'MATLAB';
stringToConvert = lower(stringToConvert);
ASCII = double(stringToConvert) - 96;
value = sum(lookup(ASCII));
Lo and behold... we get:
value =
10
The last line of the above code is crucial. Basically, ASCII will contain a bunch of indexing locations where each number corresponds to the numerical position of where the letter occurs in the alphabet. We use these positions to look up what point / score each letter gives us, and we sum over all of these values.
Part #2
The next part where double point values and double words come to play can be found in my other StackOverflow post here:
Calculate Scrabble word scores for double letters and double words MATLAB
Convert from string to ASCII:
>> myString = 'hello, world';
>> ASCII = double(myString)
ASCII =
104 101 108 108 111 44 32 119 111 114 108 100
Sum up the values:
>> total = sum(ASCII)
total =
1160
The MATLAB help for char() says (emphasis added):
S = char(X) converts array X of nonnegative integer codes into a character array. Valid codes range from 0 to 65535, where codes 0 through 127 correspond to 7-bit ASCII characters. The characters that MATLAB® can process (other than 7-bit ASCII characters) depend upon your current locale setting. To convert characters into a numeric array, use the double function.
ASCII chart here.

Convert HEX to Decimal value? w/ an example

My professor has assured me this example is correct but I can not back into it. I need to convert the mac of my printer to decimal so I can find the decimal value.
In the example he gave me, I have tried this on several online converters and I can not replicate it. What am I missing here, I searched stack I see some examples but I can not reproduce this so this is no duplicate.
MAC = AA:BB:CC:00:11:22, converted to decimal would be 170.187.204.0.17.34
A mac address has a size of 6 byte. This bytes are seperated by colons.
To convert the mac address to decimal you have to convert these single bytes.
So hex AA would be 140 decimal, BB=187 and CC=204 and so on...
A MAC address has six groups of two hexadecimal digits. In this case you can think of ':' as periods to make it easier. So if MAC = AA:BB:CC:00:11:22 = AA.BB.CC.00.11.22 you'll separately convert each of the six hexadecimal groups to decimal form.
When converting from hex to decimal, I like to use exponential notation so I know I'm getting the right answer. After some practice, you pick it up can can do the conversions on sight.
(2nd digit x 161) + (1st digit × 160)
So starting from the right of the address, going through
AA.BB.CC.00.11.22hex group by group looks like:
a.b.c.d.e.f
Remember:
A = 10, B = 11, C = 12, D = 13, E = 14, F = 15
a.
(10 x 161) + (10 × 160) = 170dec
b.
(11 x 161) + (11 × 160) = 187dec
c.
(12 x 161) + (12 × 160) = 204dec
d.
(0 x 161) + (0 × 160) = 0dec
e.
(1 x 161) + (1 × 160) = 17dec
f.
(2 x 161) + (2 × 160) = 34dec
So AA:BB:CC:00:11:22 = 170.187.204.0.17.34

Resources