I am trying to change a number of integer parameters into bytes and putting them into a byte array. I have most of the required answer but the first 2 bytes in my byte array are different from the required answer. All the if statements in the code are for errors in integer format and the for loop decides how many bytes to allocate to the parameter depending on how big the integer is.
I have tried this on my mac and also Linux computers and I still get the same answer.
def composepacket (version, hdrlen, tosdscp, totallength, identification, flags, fragmentoffset, timetolive, protocoltype, headerchecksum, sourceaddress, destinationaddress):
if version != 4:
return 1
elif hdrlen < 0 or hdrlen > 15:
return 2
elif tosdscp < 0 or tosdscp > 63:
return 3
elif totallength < 0 or totallength > 65535:
return 4
elif identification < 0 or identification > 65535:
return 5
elif flags < 0 or flags > 7:
return 6
elif fragmentoffset < 0 or fragmentoffset > 8191:
return 7
elif timetolive < 0 or timetolive > 255:
return 8
elif protocoltype < 0 or protocoltype > 255:
return 9
elif headerchecksum < 0 or headerchecksum > 65535:
return 10
elif sourceaddress < 0 or sourceaddress > 4294967295:
return 11
elif destinationaddress < 0 or destinationaddress > 4294967295:
return 12
else:
list1 = [version,hdrlen,tosdscp,totallength,identification,flags,fragmentoffset,timetolive,protocoltype,headerchecksum,sourceaddress,destinationaddress]
final = bytearray()
for element in list1:
if element <= 255:
x = element.to_bytes(1,byteorder='big')
final += x
elif element <= 65535:
x = element.to_bytes(2,byteorder='big')
final += x
elif element <= 16777215:
x = element.to_bytes(3,byteorder='big')
final += x
elif element <= 4294967295:
x = element.to_bytes(4,byteorder='big')
final += x
return final
the test line is
print(composepacket(4,5,0,1500,24200,0,63,22,6,4711, 2190815565, 3232270145))
The expected answer is
bytearray(b'E\x00\x05\xdc^\x88\x00?\x16\x06\x12g\x82\x951M\xc0\xa8\x87A')
and the answer I get is
bytearray(b'\x04\x05\x00\x05\xdc^\x88\x00?\x16\x06\x12g\x82\x951M\xc0\xa8\x87A')
so the difference is the first two bytes where i get b'\x04\x05 where i should get b'E
It looks like you're working on building out a IPv4 packet header (you should've mentioned this in your question, assuming you know this to be the case).
Your logic currently takes the version and appends it to your byte array as a whole byte (8 bits), but it should only occupy the first 4 bits (or 1 nibble).
You're likely expecting the first byte to be "E" because 0b0100_0101 (that is, 4 represented as 4 bits followed by 5 represented as 4 bits, as shown in the diagram below) is 69 in decimal, which is the ASCII character for "E". So, if you were to run strings or hexdump on a TCPv4 packet, you might see "E" as the first character. However, the first byte should actually be 0x45, so you're confusing the representations of the initial byte.
Your code isn't quite right because it's treating the version and hdrlen as two separate bytes when they should be in the same byte as two separate nibbles.
So, you want something like:
first_byte = version << 4 | length
This should give you enough direction. Best of luck.
Related
I would like to know if an integer's binary representation has an odd number of bits equal to one.
There is a trivial solution by manipulating bytes and using a few shifts but I think that it is more costly than using a XOR of every bits.
Is there a way to manipulate bits directly instead of bytes ?
int type is unbounded in python so this could be one way:
number = 34
i = 0
for n in bin(number):
if n == '1':
i += 1
if i % 2 == 0:
print('even')
else:
print('odd')
I wanted to try an alternative for not having to use strings.
number = 4
mask = 1 << (int.bit_length(number) - 1) if number > 0 else 0
ones = 0
while mask > 0:
if number & mask > 0:
ones += 1
mask >>= 1
if bool(ones % 2):
print('odd')
else:
print('even')
Just a comment: I had to handle the exception in case the number has the value 0 because, in this case, the 'bit_length' method of the 'int' class returns 0.
mask = 1 << (int.bit_length(number) - 1) if number > 0 else 0
I disagree because at least one bit is needed to represent the value 0 . After that it can be turned on or off but at least one is required. For example the 'bin' function with parameter 0 returns '0b0' and not '0b' or ''.
>>> bin(0)
'0b0'
I think int.bit_length(0) should return 1. Pyton tooltip tells: "Number of bits necessary to represent self in binary".
While practicing recursion I came across a question to reverse an integer using recursion. I tried to do the question without converting the integer into a string.
I was able to solve the question partially but the output would always come without any of the zeroes from the original input. Below is the code I came up with:
def reverseNumber(n):
if (n//10) == 0:
return n
lastDigit = n%10
ans = reverseNumber(n//10)
nod = 0
for i in str(ans):
nod += 1
return (10**nod)*lastDigit + ans
Upon inspection I could see that this was happening because when lastDigit is 0 it only returned the reversed integer from the recursive call i.e input 4230 will give 324.
But this also meant that all zeroes between the original input would also get removed as we went deeper in the recursive calls.
So please tell me how to modify this code so that zeroes in the original input are not removed while reversing.
You probably need just this:
def rev(n):
if n>0:
return str(n%10)+rev(n//10)
else:
return ''
reverseNumber should return an int and accept positive and negative numbers.
The simplest way to fix your code, without handling negative numbers, is:
def reverseNumber(n):
if n == 0:
return 0
lastDigit = n%10
n //= 10
return int(str(lastDigit) + str(reverseNumber(n))) if n else lastDigit
for test in (0, 123, 120):
print(test, reverseNumber(test))
Prints:
0 0
123 321
120 21
Yes! The reverse of 120 is 21 when you are dealing with int types as opposed to str types.
Another implementation that does handle negative numbers takes a whole different approach:
I have broken this out into two functions. Function rev is a generator function that assumes that it is being called with a positive, non-negative number and will recursively yield successive digits of the number in reverse. reverseNumber will join these numbers, convert to an int, adjust the sign and return the final result.
def reverseNumber(n):
def rev(n):
assert n >= 0
yield str(n % 10)
n //= 10
if n != 0:
yield from rev(n)
if n == 0: return 0 # special case
x = int(''.join(rev(abs(n))))
return x if n >= 0 else -x
tests = [0, 132, -132, 120]
for test in tests:
print(test, reverseNumber(test))
Prints:
0 0
132 231
-132 -231
120 21
For all non-negative n, when n < 10 it is a single digit and already the same as its reverse -
def reverse(n = 0):
if n < 10:
return str(n)
else
return str(n%10) + rev(n//10)
you can also try the following Python3 code. It will cover positive and negative integers to be reversed as integers - not as strings ...
x = int(input("What integer shall be reversed? "))
n = abs(x) # ... to handle negative integers
r = 0 # ... will hold the reversed int.
while n > 0: # Recursion part reversing int.
r = (r * 10) + (n % 10) # using '%' modulo
n = int(n / 10) # and a 'dirty way' to floor
if x < 0: # Turn result neg. if x was neg.
return (r * -1)
else:
return r # Keep result pos. if x was pos.
This approach will leave your zeros in the middle of the integer intact, though it will make any zero at the end of the initial number vanish - rightfully so as integers do not start with a zero. ;))
I'm trying to create a function that take two parameters: D = digit (0-9) and n = positive number.
If the D is parity number, the function should give me 0 but ,if the D is odd number, the function should count numbers of odd number I have in n.
There is a problem with this code but I don't know what:
def testD(D,n):
if D % 2 == 0:
return 0
count = 0
while n > 0:
if(n%10) %2==1:
count +=1
n=n/10
return count
I changed 2 things :
while n > 1: instead of while n > 0: otherwise your loop never stops
n=n//10 instead of n=n/10, where // is the euclidian division, which is what you need here
You should try this :
def testD(D,n):
if D % 2 == 0:
return 0
count = 0
while n > 1:
if(n%10) %2==1:
count +=1
n=n//10
return count
print(testD(7, 555))
# output : 3 (because 7 is odd, and there is 3 odd digits in 555)
I failed an interview earlier this morning on this question, and haven't been able to figure out why. Can anyone help me out?
An expression consisting of operands and binary operators can be written in Reverse Polish Notation (RPN) by writing both the operands followed by the operator. For example, 3 + (4 * 5) can be written as "3 4 5 * +".
You are given a string consisting of x's and *'s. x represents an operand and * represents a binary operator. It is easy to see that not all such strings represent valid RPN expressions. For example, the "x*x" is not a valid RPN expression, while "xx*" and "xxx**" are valid expressions. What is the minimum number of insert, delete and replace operations needed to convert the given string into a valid RPN expression?
5
x
xx*
xxx**
*xx
xx*xx**
OUTPUT
0
0
0
2
0
Code so far:
import fileinput
def solution (rpn):
xs = 0
numReplaces = 0
numDeletes = 0
numInserts = 0
for i in xrange(len(rpn)):
if rpn[i] == 'x':
xs += 1
elif rpn[i] == '*':
if xs > 1:
xs -= 1
elif xs == 1:
if numDeletes > 0:
numReplaces += 1
numDeletes -= 1
else:
if i == len(rpn)-1:
numInserts += 1
else:
numDeletes += 1
else:
if numDeletes > 1:
numDeletes -= 2
numReplaces += 2
else:
numDeletes += 1
while xs > 1:
if xs > 2:
numReplaces += 1
xs -= 2
if xs == 2:
numInserts += 1
xs -= 1
return numReplaces + numDeletes + numInserts
first = True
for line in fileinput.input():
if first:
numCases = int(line)
first = False
else:
print solution(line)
I think the way to start is that RPM evaluation can be performed easily by maintaining a stack of operands. For a valid input string, when you hit an operator, you pop the last two values off the stack, apply the operator and push the result back on to the stack.
Therefore, we need to find the value added by each of the "fixes":
Insert
Operand: you hit an operator, and there is only one item on the stack
Operator: You finish the string and there are multiple items left on the stack
Delete
Operand: you are at the end of the string. Adding operators will have the same result
Operator: there is only one item on the stack, adding an operand will have the same result. If the stack is empty, delete the operator
Replace
Operator -> operand: There is only one operand on the stack
Operand -> operator: Here be dragons. I believe that this will be useful only when you're out of operators, meaning the stack size is > 1; unfortunately, we don't know if these are direct operands or the result of operations, so we'll just add n-1 operators to condense the stack into a result.
I'm not 100% sure on these, but it sounds like any error condition can be handled by any of these, at equal cost, so:
def count_errors(input_):
def tokenize(input_):
''' for our purposes, each character is a token '''
for char in input_:
yield char
def is_operator(val):
return val == '*'
def is_operand(val):
return val == 'x'
stack = []
error = 0
for token in tokenize(input_):
if is_operand(token):
stack.append(token)
elif is_operator(token):
if len(stack) >= 2:
stack.pop()
stack.pop()
stack.append('x')
elif len(stack) == 1:
stack.pop()
stack.append('x')
errors += 1
else:
errors += 1
if len(stack):
return errors + len(stack) - 1
else:
return errors + 1
I have an 'if-elif-else' block and if a value is within that range it is assigned a certain value. However it when I run it just assigns it the value in the else block. This is my code:
if mile < 300:
mileInfo['miles'] = 1
elif mile>=300 and mile <2000:
mileInfo['miles'] = 2
elif mile>=2000 and mile <5000:
mileInfo['miles'] = 3
else:
mileInfo['miles'] = 4
Mile returns a float, but I thought that this didn't matter as much as in Java for example.
Thanks
Maybe mile is a string containing a number? It will not be automatically converted.
>>> "1" < 100
False
>>> "1" == 1
False
You don't need to have the elif re-check that the previous if was false. If the value wasn't < 300, it is guaranteed to be >=300.
The issue was that 'mile' was a string and as pointed out by other members string is not automatically converted. So I changed code to:
mileInt = int(float(mile))
if mileInt < 300:
mileInfo['miles'] = 1
elif mileInt < 2000:
mileInfo['miles'] = 2
elif mileInt < 5000:
mileInfo['miles'] = 3
else:
mileInfo['miles'] = 4
Using print type(mile) helps check what the type is.