I am trying to increment a binary sequence in python while maintaining the bit length.
So far I am using this piece of code...
'{0:b}'.format(long('0100', 2) + 1)
This will take the binary number, convert it to a long, adds one, then converts it back to a binary number. Eg, 01 -> 10.
However, if I input a number such as '0100', instead of incrementing it to '0101', my code
increments it to '101', so it is disregarding the first '0', and just incrementing '100'
to '101'.
Any help on how to make my code maintain the bit length will be greatly appreciated.
Thanks
str.format lets you specify the length as a parameter like this
>>> n = '0100'
>>> '{:0{}b}'.format(long(n, 2) + 1, len(n))
'0101'
That's because 5 is represented as '101' after conversion from int(or long) to binary, so to prefix some 0's before it you've use 0 as filler and pass the width of the initial binary number while formatting.
In [35]: b='0100'
In [36]: '{0:0{1:}b}'.format(long(b, 2) + 1,len(b))
Out[36]: '0101'
In [37]: b='0010000'
In [38]: '{0:0{1:}b}'.format(long(b, 2) + 1,len(b))
Out[38]: '0010001'
This is probably best solved using format strings. Get the length of your input, construct a format string from it, and then use it to print the incremented number.
from __future__ import print_function
# Input here, as a string
s = "0101"
# Convert to a number
n = long(s, 2)
# Construct a format string
f = "0{}b".format(len(s))
# Format the incremented number; this is your output
t = format(n + 1, f)
print(t)
To hardcode to four binary places (left-padded by 0) you would use 04b, for five you would use 05b, etc. In the code above we just get the length of the input string.
Oh, and if you input a number like 1111 and add 1 you'll get 10000 since you need an extra bit to represent that. If you want to wrap around to 0000 do t = format(n + 1, f)[-len(s):].
Related
I have a set of numbers and I need to generate a string-hash that is sortable for these numbers. The numbers can be integers or floats, for example:
-5.75E+100
-4
-1.74E-101
1.74E-101
5
9
11
52.3
5.75E+100
I think to do non-exponents for integers and floats it would be simple:
# whatever the padding needs to be
>>> sorted(map(lambda x: str(x).zfill(10), [-4, 5, 52.3]))
['-000000004', '0000000005', '00000052.3']
However, what would be a more comprehensive way to generate a string-hash here that would sort properly for the above list of numbers? I am fine prepending exponents, if necessary (or converting everything to an exponent, if required), and encoding negative numbers in complement code, if that's required too.
Every float object has a built-in function hex() that will convert it to a hex string. That's almost enough to make a sortable string, but there are a few problems.
First, negative numbers have a leading - but positive numbers don't have anything. You need to add a leading character to positive numbers.
Second, - comes after + in the sorting order. You need to replace one or the other to make the order correct.
Third, the exponent comes at the end of the string. It needs to get moved to the front of the string to make it more significant, but the sign needs to stay at the absolute front.
Fourth, the exponent is a variable number of digits. It needs to be zero filled so that it has a consistent size.
Putting it all together produces something like this:
def sortable_string(number):
hex_num = float(number).hex()
if not hex_num.startswith('-'):
hex_num = '+' + hex_num
hex_num = hex_num.replace('-', '!')
hex_parts = hex_num.split('p')
exponent = hex_parts[1][0] + hex_parts[1][1:].ljust(4, '0')
return hex_parts[0][0] + exponent + hex_parts[0][1:]
You can try this,
nums = sorted(map(eval, data))
nums = list(map(str, nums))
nums
Output -
['-5.75E+100', '-4', '-1.74E-101', '1.74E-101', '5', '52.3', '5.75E+100']
I am using the itertool function to enter value to a list. The itertool function is taking the value as a str, not as an int. After that, I need to convert the values from the list to its Binary equivalent. The problem arises when I need to convert a negative value e.g. -5. My code is taking the "-" as a str, but I need it to consider it as a negative sign before the following numerical value.Does the concept of unsigned integer come into play?
My code is-
L3= list(itertools.repeat("-1",5))
file= open(filename, 'w')
L3_1=[ ]
for item in L3:
x3=bytes(item,"ascii")
L3_1.append(' '.join(["{0:b}".format(x).zfill(8) for x in x3]))
for item in L3_1:
file.write("%s\n" % item)
file.close()
It's not entirely clear what your problem is and what you want to achieve, so please correct me if I make wrong assumptions.
Anyways, converting integers to binary representation is easily done using bin. For example, bin(5) gives you '0b101'. Now, bin(-5) gives you '-0b101' - which is not what you expect when being used to binary from other languages, e.g. C.
The "problem" is that integers in python are not fixed size. There's no int16, int32, uint8 and such. Python will just add bits as it needs to. That means a negative number cannot be represented by its complement - 0b11111011 is not -5 as for int8, but 251. Since binaries are potentially infinite, there's no fixed position to place a sign bit. Thus, python has to add the explicit unary -. This is different from interpreting -5 as the strings "-" and "5".
If you want to get the binary representation for negative, fixed size integers, I think you have to do it by yourself. A function that does this could look like this:
def bin_int(number, size=8):
max_val = int('0b' + ('1'* (size - 1)), 2) # e.g. 0b01111111
assert -max_val <= number <= max_val, 'Number out of range'
if number >=0:
return bin(number)
sign = int('0b1' + ('0' * size), 2) # e.g. 0b10000000
return bin(number + sign)
Now, to do what you initially wanted: write the binary representation of numbers to a file.
output_list = [1, -1, -5, -64, 0] # iterable *containing* integers
with open(filename, 'w') as output_file: # with statement is safer for writing
for number in output_list:
output_file.write(bin_int(number) + '\n')
Or if you just want to check the result:
print([bin_int(number) for number in [1, -1, -5, -64, -127]])
# ['0b1', '0b11111111', '0b11111011', '0b11000000', '0b10000001']
Note that if you want to strip the 0b, you can do that via bin_int(number)[2:], e.g. output_file.write(bin_int(number)[2:] + '\n'). This removes the first two characters from the string holding the binary representation.
I have written an expression which will ask for a user input. Based on the user input, it will calculate a value. If the calculated value is say 1, then I want the value to be converted to 0001. Same thing applies when the calculated value is 2 and 3 digits long.
If the calculated value is 4 or 5 digits long, then I don't want any modification on it. This value is used in the later part of the program which I have not mentioned here.
import numpy as np
FT_init = 3.1212
delt = 0.15
TS_init = 165
flowtime = input("Enter the flow time required: ")
timestep = (flowtime-FT_init)/delt
timestep = round(timestep + TS_init)
print timestep
I request your help on this.
You may use zfill() string method:
str(timestep).zfill(4)
This is more or less similar to the other answer.
i = 9
print("{:05d}".format(i))
just change the print to use a format string:
print '%04d' % int(timestep)
that will zero fill left, and allow it to show 5 digits without problem
however you cannot use that output in any kind of calculations since converting back to a number will strip the left zeros and possibly use it as an octal number - which will cause a conversion error if there are digits that would not be valid octal i.e. 0397
Use the string.format() method. The following format specification, '{:04}', says replace that with the argument n from format(n) and then format it, :, with leading zeros, 0, printing at least 4, 4, digits.
Example with numbers of different printed widths:
for n in [1, 12, 123, 1234, 12345, 123456]:
print('{:04}'.format(n))
Output:
0001
0012
0123
1234
12345
123456
I need to record SerialNumber(s) on an object. We enter many objects. Most serial numbers are strings - the numbers aren't used numerically, just as unique identifiers - but they are often sequential. Further, leading zeros are important due to unique id status of serial number.
When doing data entry, it's nice to just enter the first "sequential" serial number (eg 000123) and then the number of items (eg 5) to get the desired output - that way we can enter data in bulk see below:
Obj1.serial = 000123
Obj2.serial = 000124
Obj3.serial = 000125
Obj4.serial = 000126
Obj5.serial = 000127
The problem is that when you take the first number-as-string, turn to integer and increment, you loose the leading zeros.
Not all serials are sequential - not all are even numbers (eg FDM-434\RRTASDVI908)
But those that are, I would like to automate entry.
In python, what is the most elegant way to check for leading zeros (*and, I guess, edge cases like 0009999) in a string before iterating, and then re-application of those zeros after increment?
I have a solution to this problem but it isn't elegant. In fact, it's the most boring and blunt alg possible.
Is there an elegant solution to this problem?
EDIT
To clarify the question, I want the serial to have the same number of digits after the increment.
So, in most cases, this will mean reapplying the same number of leading zeros. BUT in some edge cases the number of leading zeros will be decremented. eg: 009 -> 010; 0099 -> 0100
Try str.zfill():
>>> s = "000123"
>>> i = int(s)
>>> i
123
>>> n = 6
>>> str(i).zfill(n)
'000123'
I develop my comment here, Obj1.serial being a string:
Obj1.serial = "000123"
('%0'+str(len(Obj1.serial))+'d') % (1+int(Obj1.serial))
It's like #owen-s answer '%06d' % n: print the number and pad with leading 0.
Regarding '%d' % n, it's just one way of printing. From PEP3101:
In Python 3.0, the % operator is supplemented by a more powerful
string formatting method, format(). Support for the str.format()
method has been backported to Python 2.6.
So you may want to use format instead… Anyway, you have an integer at the right of the % sign, and it will replace the %d inside the left string.
'%06d' means print a minimum of 6 (6) digits (d) long, fill with 0 (0) if necessary.
As Obj1.serial is a string, you have to convert it to an integer before the increment: 1+int(Obj1.serial). And because the right side takes an integer, we can leave it like that.
Now, for the left part, as we can't hard code 6, we have to take the length of Obj1.serial. But this is an integer, so we have to convert it back to a string, and concatenate to the rest of the expression %0 6 d : '%0'+str(len(Obj1.serial))+'d'. Thus
('%0'+str(len(Obj1.serial))+'d') % (1+int(Obj1.serial))
Now, with format (format-specification):
'{0:06}'.format(n)
is replaced in the same way by
('{0:0'+str(len(Obj1.serial))+'}').format(1+int(Obj1.serial))
You could check the length of the string ahead of time, then use rjust to pad to the same length afterwards:
>>> s = "000123"
>>> len_s = len(s)
>>> i = int(s)
>>> i
123
>>> str(i).rjust(len_s, "0")
'000123'
You can check a serial number for all digits using:
if serial.isdigit():
How can we get the length of a hexadecimal number in the Python language?
I tried using this code but even this is showing some error.
i = 0
def hex_len(a):
if a > 0x0:
# i = 0
i = i + 1
a = a/16
return i
b = 0x346
print(hex_len(b))
Here I just used 346 as the hexadecimal number, but my actual numbers are very big to be counted manually.
Use the function hex:
>>> b = 0x346
>>> hex(b)
'0x346'
>>> len(hex(b))-2
3
or using string formatting:
>>> len("{:x}".format(b))
3
While using the string representation as intermediate result has some merits in simplicity it's somewhat wasted time and memory. I'd prefer a mathematical solution (returning the pure number of digits without any 0x-prefix):
from math import ceil, log
def numberLength(n, base=16):
return ceil(log(n+1)/log(base))
The +1 adjustment takes care of the fact, that for an exact power of your number base you need a leading "1".
As Ashwini wrote, the hex function does the hard work for you:
hex(x)
Convert an integer number (of any size) to a hexadecimal string. The result is a valid Python expression.