The logic behind implementation of ord() in Lutz's "Learning Python " - python

I can't wrap my head around the example implementation of ord() function given in this book:
>>> B = '1101' # Convert binary digits to integer with ord
>>> I = 0
>>> while B != '':
... I = I * 2 + (ord(B[0]) - ord('0'))
... B = B[1:]
...
>>> I
13
Particurlarly I can't understand what are we achieving with this calculation 'I = I * 2 + (ord(B[0]) - ord('0'))'? Can anybody please explain step by step what this program does?

The expression (ord(B[0]) - ord('0')) is a very cumbersome way of doing int(B[0]).
The ord function returns the numeric value of the Unicode codepoint for a single character string. For digits and characters from the Latin alphabet, that's the ASCII value, somewhere between 0 and 127. For more exotic characters (like accented vowels, or Chinese characters), you'll get a larger number. A feature of the ASCII character set is the the numeric characters are arranged in order. Zero is character 48, one is character 49 and so on. That means you can do math on the ord values and it may correspond to doing math on the numbers themselves. If you subtract ord('0') from the ord of some other digit character, you'll get that other character's value.
But Python has better ways to do that, most of the time. It's a whole lot clearer if you convert a string into an integer with int, rather than using math with ord. I have no idea why the book you're reading would suggest doing it that way, unless learning about ord was the point of the exercise. And actually there's a lot of weird stuff in that code example. Using a for loop is a much more natural way to iterate over the characters of a string, rather than using slicing and a while loop, while constantly looking up the string's first character.
If I couldn't use int(some_string, 2) to covert a binary string to a number, I'd write:
def convert_binary_to_int(bin_str):
val = 0
for char in bin_str:
val *= 2
val += int(char) # or maybe use char == '1', if you can't call int at all
return val
As I commented in the code, if you can't use int at all, an alternative for converting each binary digit might be char == '1', which will be True or False. Those values are equal to 1 and 0, respectively, which is in fact the numerical value you want!

So I've figured out the answer to my question. I couldn't understand the math behind this code, why we need to start with 0 and then multiply by 2, etc. Turns out it's just the reverse of repeating division-by-2 method. E.g 13 is 1101 in binary, and one way of converting it is below
13|2 rem 1
6 |2 rem 0
3 |2 rem 1
1 |2 rem 1
0
Now we just have to start from the bottom, that means
0 * 2 + rem 1 = 1
1 * 2 + rem 1 = 3
3 * 2 + rem 0 = 6
6 * 2 + rem 1 = 13
Guess I have probably worded my question incorrectly.

Related

A function that takes in a string of numbers and returns the integer without the use of the built-in int() function [duplicate]

This question already has answers here:
Convert String to Int without int()
(4 answers)
Closed 2 years ago.
I need to create a function that takes in a string e.g. '142' and return it as an integer, without the use of the int() function. I'm not sure where to start at all and the 'hint' provided to us is to use a list such as
digits = list('0123456789')
edit: We have not yet learnt chr, ord, eval() or ast.literal_eval? We have not yet learnt what string and integer literals are nor have we learnt dictionaries. for loops as well as 'in' are discouraged as well.
Does anyone have any ideas as to how to approach this?
From '5768' you can get 8 * 1 + 6 * 10 + 7 * 100 + 5 * 1000. You can use a loop to access the characters of the string and you have to keep track of the multiplier.
index can be used to find the position of the current character in the list and then you have the correct integer value for multiplication.
digits = list('0123456789')
value = 0
exp = 0
for c in reversed('5768'):
print(f'c={c} exp={exp}')
i = digits.index(c)
value += i * 10 ** exp
exp += 1
print(value)
After getting some more constraints in the question this code can be adjusted to the following.
digits = list('0123456789')
number = '5768'
value = 0
character_position = 0
while character_position < len(number):
i = digits.index(number[character_position])
value += i * 10 ** (len(number) - character_position - 1)
character_position += 1
print(value)
A one liner solution:
print(sum('0123456789'.index(c) * 10 ** exp for exp, c in enumerate(reversed('5768'))))
Convert to int using eval:
str = '0123456789'
def str_to_int(str):
return eval(str.lstrip("0"))
print(str_to_int(str))
print(type(str_to_int(str)))
Returns:
123456789
<class 'int'>

How print("YNEOS"[(w%2)|(w<=2)::2]) works

I was just trying to solve this problem on Codeforces: Check whether it's posible to split a number w (1 ≤ w ≤ 100) into a sum of 2 even numbers
I solved the problem and started to look others solutions for the problem. The I found that solution:
w=int(input())
print("YNEOS"[(w%2)|(w<=2)::2])
it took half of time to solve the problem then mine. Unfortunately I am not getting how it is working and why it is faster than mine. My solution is :
n = int(input())
if (n-2)%2==0 and n > 2:
print("YES")
else:
print("NO")
I am a beginner in python. So it will be very helpful for me it i get a proper explanation.
The :: part is called slicing. The general syntax is start:stop[:step] which will make a new array or string from the original one, beginning from index start to before stop every step (default = 1). It's essentially a syntactic sugar for slice(start, stop, step) which returns a slice object. If stop is omitted then all the elements till the end of the string will be extracted
Understanding slice notation
How do I use the slice notation in Python?
https://docs.python.org/2.3/whatsnew/section-slices.html
You may want to read An Informal Introduction to Python for more information about slicing
Now (w%2)|(w<=2) calculates the start index. | is the bitwise-OR operator. w<=2 is a bool expression, but in Python "Booleans are a subtype of integers", so True and False will be converted to 1 and 0 respectively
If w is an odd number then w % 2 == 1. Regardless of the remaining part, (w%2)|(w<=2) will always be 1 in this case and the expression becomes "YNEOS"[1::2] which takes every second letter in the string starting from index 1. The result is the string NO
If w is an even number then w % 2 == 0. According to the problem description 1 ≤ w ≤ 100 the only valid even numbers belong to the range [2, 100]
If w == 2 then w <= 2 returns 1 and the output is NO like above
If w > 2 then both the sides of (w%2)|(w<=2) is 0, and "YNEOS"[0::2] takes the 1st, 3rd and 5th letters which is YES
Realizing that the expression always returns 0 or 1 we'll have an alternative more readable solution that uses direct addressing instead of slicing
w=int(input())
print(['YES', 'NO'][(w % 2) | (w <= 2)])
Btw, you have a redundant subtraction: (n-2)%2==0 is exactly the same as n % 2 == 0

incrementing to numbers that are led by zeros

There are many questions regarding to turning an integer to a number led by zeros, But i couldn't find any solutions to incrementing string that is already led by zeros.
Python already transforms number led by zero to normal integer:
>>> 0001
1
>>> int(0001)
1
By considering that, whenever i add two numbers led by zero to each other, i get a normal integer:
>>> 0001 + 0001
2
>>> int('0001') + int('0001')
2
But, what i am trying to find out is for example, how to get a sum such as 0002 when adding two 0001's to each other.
Obviously it should be printed out as string type, since Python transforms number led by zero to normal integer.
Please also consider some cases like this:
x = 0001
How can i increment x by 1 without specifying zeros?
Is there any Pythonic way to do this? With solution working on all cases of numbers led by zero? ('0001' + '0001' == '0002' and '01' + '01' == '02', For example).
If the strings have the same length, you can simply apply zfill on the output using the length of one of the operands:
def add(x, y) -> str: # remove type hint for Python 2
return str(int(x) + int(y)).zfill(len(x))
print(add('0001', '0025'))
# '0026'
To accomodate string inputs of mismatching lengths, you can pass max(len(x), len(y)) to zfill so that the output is zero padded using the length of the longer string:
def add(x, y) -> str:
return str(int(x) + int(y)).zfill(max(len(x), len(y)))
print(add('0001', '25'))
# 0026
How about this:
x = '00001'
y = '00002'
print '{0:0{width}}'.format(int(x)+int(y), width=max(len(x), len(y)))
prints 00003

read single bit operation python 2.6

I am trying to read a single bit in a binary string but can't seem to get it to work properly. I read in a value then convert to a 32b string. From there I need to read a specific bit in the string but its not always the same. getBin function returns 32bit string with leading 0's. The code I have always returns a 1, even if the bit is a 0. Code example:
slot=195035377
getBin = lambda x, n: x >= 0 and str(bin(x))[2:].zfill(n) or "-" + str(bin(x))[3:].zfill(n)
bits = getBin(slot,32)
bit = (bits and (1 * (2 ** y)) != 0)
print("bit: %i\n"%(bit))
in this example bits = 00001011101000000000000011110011
and if I am looking for bit3 which i s a 0, bit will be equal to 1. Any ideas?
To test for specific bits in a integer value, use the & bitwise operand; no need to convert this to a binary string.
if slot & (1 << 3):
print 'bit 3 is set'
else:
print 'bit 3 is not set'
The above code shifts a test bit to the left twice. Alternatively, shift slot to the right 3 times:
if (slot >> 2) & 1:
To make this generic for any bit position, subtract 1:
if slot & (1 << (bitpos - 1)):
print 'bit {} is set'.format(bitpos)
or
if (slot >> (bitpos - 1)) & 1:
Your binary formatting code is overly verbose. Just use the format() function to create a binary string representation:
format(slot, '032b')
formats your binary value to a 0-padded 32-character binary string.
n = 223
bitpos = 3
bit3 = (n >> (bitpos-1))&1
is how you should be doing it ... don't use strings!
You can just use slicing to get the correct digit.
bits = getBin(slot, 32)
bit = bits[bit_location-1:bit_location] #Assumes zero based values
print("bit: %i\n"%(bit))

Bitwise subtraction in Python

This is a follow-up to my question yesterday:
CMS kindly provided this example of using bitwise operators to add two numbers in C:
#include<stdio.h>
int add(int x, int y) {
int a, b;
do {
a = x & y;
b = x ^ y;
x = a << 1;
y = b;
} while (a);
return b;
}
int main( void ){
printf( "6 + 3 = %d", add(6,3));
printf( "6 - 3 = %d", add(6,-3));
return 0;
}
It works great and I then ported it to Python as follows:
def add(x, y):
while True:
a = x & y
b = x ^ y
x = a << 1
y = b
if a == 0:
break
return b
print "6 + 3 = %d" % add(6,3)
print "6 - 3 = %d" % add(6,-3)
They both work for addition and the C program works for subtraction as well. However, the Python program enters an infinite loop for subtraction. I am trying to get to the bottom of this and have posted the program here for further experimentation: http://codepad.org/pb8IuLnY
Can anyone advise why there would be a difference between the way C handles this and the way CPython handles this?
As I pointed out in my response to CMS' answer yesterday, left-shifting a negative number is undefined behavior in C so this isn't even guaranteed to work in C (the problem is how to handle the signed bit, do you shift it like a value bit or is it not affected by a shift? The standards committee couldn't agree on a behavior so it was left undefined).
When this happens to work in C it relies on fixed bit-width integers so that the leftmost bit gets pushed off the end when you do a shift (it also requires the sign bit to be treated as a value bit for shifting purposes). All integer types in C are fixed-bit but Python numbers can be arbitrarily large. Left-shifting a number in Python just causes it to keep getting larger:
>>> 1 << 100
1267650600228229401496703205376L
You could try something like this:
x = (a << 1) & 0xffffffff
To limit the result to 32-bits, the problem is that the left shift operator in Python doesn't shift the sign bit of a signed number (which is part of what is required to make this particular solution work). There might be a way to change the behavior of the shift operator but I don't know how.
Shifting negative numbers doesn't have consistent interpretation between python and C.
if i, j are two integers:
addition:
printf("%d",(i^j)|((i&j)<<1));
I've noticed that you're assuming that python works with numbers the same way as C does.
Thats not entirely true. Meaning C's int numbers have a fixed length of 16 bits. For detailed info on C datatypes you can refer to C_data_types on en.wikipedia.org
Python, on the other hand, is said to have a virtually infinite length for int numbers.
Adding positive integers may work the same way. But subtracting or adding negative integers shouldn't be a simple mapping translation.
An easy way to understand this is a little example on negative numbers:
Imagine a fixed length integer representation of 3 bits:
#Unsigned#
000 : 0
001 : 1
010 : 2
011 : 3
100 : 4
101 : 5
110 : 6
111 : 7
#Signed:#
000 : 0
001 : 1
010 : 2
011 : 3
100 : -4
101 : -3
110 : -2
111 : -1
This works cool because you can see that 1-3=1+(-3), -3 is 101 that's 5 if unsigned. So 1+5=6, 6 : 110 : -2. This means that 1-3=-2.
it also becomes buggy when overflowing:
-4 + -1 = 3 not -5 because it's out of range!
3 + 1 = -4 not 4 because it's out of range!
As you may see this works for fixed length but it doesn't work this way in Python.
For anyone are still interested, to resolve issue in python, just add a new case and switch the order of x and y inside the function, and return the negative value, though this put "-" in the function, but this presented a way using bit-wise operator. For anyone still wish to argue using operator "-" in the following question, I could argue that for the case of 2 - 6, the right answer is -4 where "-" exists in the answer, so it might be okay to add it when x is smaller than y. Hope this helps.
#A substract to substract two integers using bits operators
#refer to: https://www.geeksforgeeks.org/subtract-two-numbers-without-using-arithmetic-operators/
def subtractBits(x, y):
xRAW = x
yRAW = y
if x < y:
x = y
y = xRAW
# Iterate till there
# is no carry
while (y != 0):
# borrow contains common
# set bits of y and unset
# bits of x
borrow = (~x) & y
# Subtraction of bits of x
# and y where at least one
# of the bits is not set
x = x ^ y
# Borrow is shifted by one
# so that subtracting it from
# x gives the required sum
y = borrow << 1
if xRAW < yRAW:
return -x
else:
return x
print(subtractBits(100, 50))
print(subtractBits(1, 3))
print(subtractBits(40, 0))
print(subtractBits(0, 40))
print(subtractBits(5, 5))

Categories