Convert float number into binary - python

import struct
def print_binary(number_string):
bin = ""
if "." in number_string:
number_string = float(number_string)
bin += bin(struct.unpack('!i',struct.pack('!f', number_string)))
else:
num = int(number_string)
bin += "{0:b}".format(num)
print(bin)
I'm having trouble with converting a number with a decimal in it to binary (my if statement)
test_values = "0 1234 -1234 12.4 0.6 -12.4 -0.6 -1234567890.123456789".split()
I get an error when it gets up to 12.4

I used recursion. But there can be a recursion limit on some value here.
Here is the method I used by hand.
Fractional Part = .6875 in base 10
.6875*2 equals 1.375 whole number is 1
.375*2 equals 0.75 whole number is 0
.75*2 equals 1.5 whole number is 1
.5*2 equals 1.0 whole number is 1
Hence .6875D = .1011 in base 2
However, think about the value 12.4. It will go forever!
.4*2 = .8
.8*2 = 1.6
.6*2 = .2
.2*2 = .4
... and so on
So we have to set a limit in our recursion calculation. I made it 10. Although this does not sound like a lot, see how accurate it is.
My input of 12.4 returns 1100.0110011001 which is equal to 12.3994140625
Pretty close, feel free to play with that number, take the ceiling of it, etc.
Here is the code:
def get_integer_part(pre_decimal_string):
# special case of negative 0 being a prefix "-0.6"
if pre_decimal_string == "-0":
return "-0"
else:
num = int(pre_decimal_string)
return "{0:b}".format(num)
def get_decimal_part(post_decimal_string, string_builder, recurse):
recurse += 1
post_decimal_value = float("." + post_decimal_string)
if post_decimal_value == 0 or recurse > 10:
return string_builder
else:
temp_mult_str = str(post_decimal_value * 2)
temp_mult_split = temp_mult_str.split(".")
string_builder += temp_mult_split[0]
return get_decimal_part(temp_mult_split[1], string_builder, recurse)
def print_binary(number_string):
# handle case of no preceding 0 ".3" or
if number_string[0] == ".":
number_string = "0" + number_string
# handle case of no preceding 0 and is negative
if number_string[0:2] == "-.":
number_string = "-0" + number_string[1:]
if "." in number_string:
str_split = number_string.split(".")
print(get_integer_part(str_split[0]) + "." + str(get_decimal_part(str_split[1], "", 0)))
else:
print(get_integer_part(number_string))
test_values = "0 1234 -1234 12.4 0.6 -12.4 -0.6 -1234567890.123456789".split()
print(test_values)
for each in test_values:
print_binary(each)
# special cases
print_binary("-.7")
print_binary(".67")
Here is the final output:
0
10011010010
-10011010010
1100.0110011001
0.1001100110
-1100.0110011001
-0.1001100110
-1001001100101100000001011010010.0001111110
-0.1011001100
0.1010101110
Although I would have done this differently, I kept your code and format as much as possible to make it easiest for you to learn.

Related

My Function To Count The Largest Binary Gap Doesn't Work But I Can't Figure Out Why

I'm working through the Codility problems and I have gotten the first one almost correct. The task is to write a function which returns the longest binary gap (a sequence of 0s in between 1s) in a binary number. I have gotten all of the test numbers correct apart from 9, which should be 2 (its binary representation is 1001) but which my function returns as 0. I can't seem to figure out why.
My function is as follows:
def Solution(N):
x = bin(N)[2:]
x_string = str(x)
y = (len(x_string))
count = 0
max = 0
for index, item in enumerate(x_string):
if item == "1":
count = 0
elif item == "0" and x_string[index + 1:y-1] != "0"*(y -1 - (index + 1)):
count = count + 1
if count > max:
max = count
print(max)
The complicated indexing and second condition in the elif statement is so that when a 0 is not contained between two 1s then it isn't recognised as the beginning of a binary gap e.g. when the for loop looks at the second character in bin(16) = 10000, it doesn't set count to 1 because all of the remaining characters in the string are also zero.
Simple solution
x_string[index + 1:y-1] != "0"
this bit wants to take a look at the whole string that's left, but the end argument isn't inclusive,it's exluded, so if string length = 4; string[0:4] is the whole string.
source: https://docs.python.org/3/tutorial/introduction.html
-Sam

problem calculating minimum amount of coins in change using python

I have a homework assignment in which we have to write a program that outputs the change to be given by a vending machine using the lowest number of coins. E.g. £3.67 can be dispensed as 1x£2 + 1x£1 + 1x50p + 1x10p + 1x5p + 1x2p.
However, my program is outputting the wrong numbers. I know there will probably be rounding issues, but I think the current issue is to do with my method of coding this.
change=float(input("Input change"))
twocount=0
onecount=0
halfcount=0
pttwocount=0
ptonecount=0
while change!=0:
if change-2>-1:
change=change-2
twocount+=1
else:
if change-1>-1:
change=change-1
onecount+=1
else:
if change-0.5>-1:
change=change-0.5
halfcount+=1
else:
if change-0.2>-1:
change=change-0.2
pttwocount+=1
else:
if change-0.1>-1:
change=change-0.1
ptonecount+=1
else:
break
print(twocount,onecount,halfcount,pttwocount,ptonecount)
RESULTS:
Input: 2.3
Output: 11010
i.e. 3.2
Input: 3.2
Output:20010
i.e. 4.2
Input: 2
Output: 10001
i.e. 2.1
All your comparisons use >-1, so you give out change as long as you have more than -1 balance.
This would be correct if you were only dealing with integers, since there >-1 is equal to >=0.
For floating point numbers however, we have for example -0.5>-1, so we will give out change for negative balance (which we do not want).
So the correct way would be to replace all >-1 comparisons by >=0 (larger or equal to 0) comparisons.
The problem is how it calculates the change using your if/else statements. If you walk through the first example change-2>-1 will register true and then result will be .3 but on the next loop the if change - 1 > -1 you are expecting to be false but it's not it's actually -0.7. One of the best ways to do this would be with Python's floor // and mod % operators. You have to round some of the calculations because of the way Python handles floats
change=float(input("Input change"))
twocount=0
onecount=0
halfcount=0
pttwocount=0
ptonecount=0
twocount = int(change//2)
change = round(change%2,1)
if change//1 > 0:
onecount = int(change//1)
change = round(change%1,1)
if change//0.5 > 0:
halfcount = int(change//0.5)
change = round(change%0.5, 1)
if change//0.2 > 0:
pttwocount = int(change//0.2)
change = round(change%0.2, 1)
if change//0.1 > 0:
ptonecount = int(change//0.1)
change = round(change%0.1,1)
print(twocount,onecount,halfcount,pttwocount,ptonecount)
But given the inputs this produces
Input: 2.3
Output: 1 0 0 1 1
Input: 3.2
Output:1 1 0 1 0
Input: 2
Output: 1 0 0 0 0

Kaprekar numbers in Python

I aas solving a problem on HackerRank and the problem is as follows:
A modified Kaprekar number is a positive whole number n with d digits, such that when we split its square into two pieces - a right hand piece r with d digits and a left hand piece l that contains the remaining d or d−1 digits, the sum of the pieces is equal to the original number (i.e. l + r = n).
Alternatively, a modified Kaprekar number is a positive whole number n with 2d digits (if its number of digits is even) or 2d + 1 digits (if its number of digits is odd), such that when we split its square into two pieces, a right hand piece r containing d or d + 1 digits, and a left piece l containing the remaining d digits, the sum of the two pieces is equal to the original number.
We need to find Kaprekar numbers within a given range. So I wrote the following piece of code:
def checkIsKaprekar( num ):
string_num = str(num**2)
if num == int(string_num[:len(string_num)//2]) + int(string_num[len(string_num)//2:]):
return True
kaprekars = [ str(i) for i in range(int(input()),int(input())) if checkIsKaprekar(i) == True ]
print (' '.join(kaprekars))
The problem with the above solution is when we pass single digit numbers, they are converted into a string of which the right half is the number itself and the left half is ''. Now I am converting these strings to int(), which throws an exception.
To avoid this situation, I changed my code to this:
def checkIsKaprekar( num ):
string_num = str(num**2)
left_string = string_num[:len(string_num)//2]
right_string = string_num[len(string_num)//2:]
left_num = int(left_string) if left_string != '' else 0
right_num = int(right_string) if right_string != '' else 0
if num == left_num + right_num:
return True
kaprekars = [ str(i) for i in range(int(input()),int(input())) if checkIsKaprekar(i) == True ]
print (' '.join(kaprekars))
But I don't like this code even though it does solve the purpose. How can I tweak my original code to produce the right output?
Link to the question: https://www.hackerrank.com/challenges/kaprekar-numbers
Is there any way I can specify a default value of 0 if the string is ''?
As answered by B.M. int('0'+string_num[:len(string_num)//2]) works perfectly. int('0'+'') produces 0.
Maybe the cleanest way would be to define a function like this:
def to_int(s)
return int(s) if s else 0
But it may not be worth the overhead in this case.
It's often convenient to solve problems on integers ... with integers:
def kaprekar(n):
l=1
while l<=n : l*=10
return n== (n*n)//l + (n*n)%l
[print(x,end=' ') for x in range(1,100) if kaprekar(x)]
# 1 9 45 55 99
def checkIsKaprekar( num ):
if(num==1):
return True
elif((num**2)<15):
return False
string_num = str(num**2)
if num == int(string_num[:len(string_num)//2]) + int(string_num[len(string_num)//2:]):
return True
You can find Kaprekar numbers within a given range by testing each number for the given condition in the given range. For example,
def print_Kaprekar_nums(start, end):
for i in range(start, end + 1):
# Get the digits from the square in a list:
sqr = i ** 2
digits = str(sqr)
# Now loop from 1 to length of the number - 1, sum both sides and check
length = len(digits)
for x in range(1, length):
left = int("".join(digits[:x]))
right = int("".join(digits[x:]))
if (left + right) == i:
print("Number: " + str(i) + "Left: " + str(left) + " Right: " + str(right))
print_Kaprekar_nums(150, 8000)
This will give the output:
Number: 297Left: 88 Right: 209
Number: 703Left: 494 Right: 209
Number: 999Left: 998 Right: 1
Number: 1000Left: 1000 Right: 0
Number: 2223Left: 494 Right: 1729
Number: 2728Left: 744 Right: 1984
Number: 4879Left: 238 Right: 4641
Number: 4950Left: 2450 Right: 2500
Number: 5050Left: 2550 Right: 2500
Number: 5292Left: 28 Right: 5264
Number: 7272Left: 5288 Right: 1984
Number: 7777Left: 6048 Right: 1729

Add numbers in hexadecimal base without converting bases?

I need to write a function which gets two numbers in hexadecimal base, and calculates the sum of both of them, I'm not allowed to convert them to decimal base, the code is supposed to calculate it "manually" using loops.
for example this is how it should work:
1
1 f 5 (A)
+ 5 a (B)
-------------
= 2 4 f
Here is an input example:
>>> add("a5", "17")
'bc'
I've started building my code but I got stuck, I thought I would divide into three ifs, one that would sum up only numbers, other sums numbers and letters, and the third one sums letters, but I don't know how to continue from here:
def add_hex(A,B):
lstA = [int(l) for l in str(A)]
lstB = [int(l) for l in str(B)]
if len(A)>len(B):
A=B
B=A
A='0'*(len(B)-len(A))+A
remainder=False
result=''
for i in range(len(B)-1)
if (A[i]>0 and A[i]<10) and (B[i]>0 and B[i]<10):
A[i]+B[i]=result
if A[i]+B[i]>10:
result+='1'
Any help is greatly appreciated, I have no clue how to start on this!
You can have a sub-function that adds two single-digit hex numbers and returns their single-digit sum and a carry (either 0 or 1). This function will take three inputs: two numbers you want to add and a carry-in. You can then loop through the digits of the two numbers you want to add from least significant to most significant, and apply this function for every pair of digits while taking into account the carry at each stage.
So let's try your example:
A 5
1 7 +
We start at the least significant digits, 5 and 7, and perform the 1-digit addition. 516 + 716 = 1210. 1210 is less than 1610, so the output of our 1-digit add is 1210 = C16 with a carry of 0.
Now we add A and 1 (our carry-in is 0 so we can just add them normally). A16 + 116 = 1110. 1110 is less than 1610, so the output of our 1-digit add is 1110 = B16 with a carry of 0. (If we had a non-zero carry-in, we would just add 1 to this value.)
Hence, our overall result is:
A 5
1 7 +
-----
B C
I think we just remember the pattern of addition. Like following.
"0" + "0" = "0"
"0" + "1" = "1"
"0" + "2" = "2"
.
.
.
"f" + "d" = "1b"
"f" + "e" = "1c"
"f" + "f" = "1e"
We have dictionary of all of the pattern because we've learned it in school or somewhere. And we've also learned carry.
So I think this seems like manual addition algorithm.
Remembering the pattern include carry.
Calculating
Translate two digit to one digit(a+b->c).
Treat carry correctly.
And here is my code for that. But it may be a bit tricky.
import itertools
def add_hex(A,B):
A = "0"+A
B = "0"+B
#Remember all pattern include carry in variable d.
i2h = dict(zip(range(16), "0123456789abcdef"))
a = [(i,j) for i in "0123456789abcdef" for j in "0123456789abcdef"]
b = list(map(lambda t: int(t[0],16)+int(t[1],16), a))
c = ["0"+i2h[i] if i<16 else "1"+i2h[i-16] for i in b]#list of digit include carry
d = dict(zip(a,c))#d={(digit,digit):digit,,,}
#Calculate with variable d.
result = ""
cur = "0"
nex = "0"
for i in itertools.izip_longest(A[::-1], B[::-1], fillvalue = "0"):
cur = d[(nex, d[i][1])][1] #cur = carry + digit + digit
if d[i][0]=='1' or d[(nex, d[i][1])][0]=='1':#nex = carry = carry + digit + digit
nex = "1"
else:
nex = "0"
result += cur
return result[::-1]
#Test
A = "fedcba"
B = "012346"
print add_hex(A,B)
print hex(int(A,16)+int(B,16))#For validation
I hope it helps. :)

python - print squares of numbers which are palindromes : improve efficiency

I have an assignment to do. The problem is something like this. You give a number, say x. The program calculates the square of the numbers starting from 1 and prints it only if it's a palindrome. The program continues to print such numbers till it reaches the number x provided by you.
I have solved the problem. It works fine for uptil x = 10000000. Works fine as in executes in a reasonable amount of time. I want to improve upon the efficiency of my code. I am open to changing the entire code, if required. My aim is to make a program that could execute 10^20 within around 5 mins.
limit = int(input("Enter a number"))
def palindrome(limit):
count = 1
base = 1
while count < limit:
base = base * base #square the number
base = list(str(base)) #convert the number into a list of strings
rbase = base[:] #make a copy of the number
rbase.reverse() #reverse this copy
if len(base) > 1:
i = 0
flag = 1
while i < len(base) and flag == 1:
if base[i] == rbase[i]: #compare the values at the indices
flag = 1
else:
flag = 0
i += 1
if flag == 1:
print(''.join(base)) #print if values match
base = ''.join(base)
base = int(base)
base = count + 1
count = count + 1
palindrome(limit)
He're my version:
import sys
def palindrome(limit):
for i in range(limit):
istring = str(i*i)
if istring == istring[::-1]:
print(istring,end=" ")
print()
palindrome(int(sys.argv[1]))
Timings for your version on my machine:
pu#pumbair: ~/Projects/Stackexchange time python3 palin1.py 100000
121 484 676 10201 12321 14641 40804 44944 69696 94249 698896 1002001 1234321
4008004 5221225 6948496 100020001 102030201 104060401 121242121 123454321 125686521
400080004 404090404 522808225 617323716 942060249
real 0m0.457s
user 0m0.437s
sys 0m0.012s
and for mine:
pu#pumbair: ~/Projects/Stackexchange time python3 palin2.py 100000
0 1 4 9
121 484 676 10201 12321 14641 40804 44944 69696 94249 698896 1002001 1234321
4008004 5221225 6948496 100020001 102030201 104060401 121242121 123454321 125686521
400080004 404090404 522808225 617323716 942060249
real 0m0.122s
user 0m0.104s
sys 0m0.010s
BTW, my version gives more results (0, 1, 4, 9).
Surely something like this will perform better (avoiding the unnecessary extra list operations) and is more readable:
def palindrome(limit):
base = 1
while base < limit:
squared = str(base * base)
reversed = squared[::-1]
if squared == reversed:
print(squared)
base += 1
limit = int(input("Enter a number: "))
palindrome(limit)
I think we can do it a little bit easier.
def palindrome(limit):
count = 1
while count < limit:
base = count * count # square the number
base = str(base) # convert the number into a string
rbase = base[::-1] # make a reverse of the string
if base == rbase:
print(base) #print if values match
count += 1
limit = int(input("Enter a number: "))
palindrome(limit)
String into number and number into string conversions were unnecessary. Strings can be compared, this is why you shouldn't make a loop.
You can keep a list of square palindromes upto a certain limit(say L) in memory.If the Input number x is less than sqrt(L) ,you can simply iterate over the list of palindromes and print them.This way you wont have to iterate over every number and check if its square is palindrome .
You can find a list of square palindromes here : http://www.fengyuan.com/palindrome.html
OK, here's my program. It caches valid suffixes for squares (i.e. the values of n^2 mod 10^k for a fixed k), and then searches for squares which have both that suffix and start with the suffix reversed. This program is very fast: in 24 seconds, it lists all the palindromic squares up to 10^24.
from collections import defaultdict
# algorithm will print palindromic squares x**2 up to x = 10**n.
# efficiency is O(max(10**k, n*10**(n-k)))
n = 16
k = 6
cache = defaultdict(list)
print 0, 0 # special case
# Calculate everything up to 10**k; these will be the prefix/suffix pairs we use later
tail = 10**k
for i in xrange(tail):
if i % 10 == 0: # can't end with 0 and still be a palindrome
continue
sq = i*i
s = str(sq)
if s == s[::-1]:
print i, s
prefix = int(str(sq % tail).zfill(k)[::-1])
cache[prefix].append(i)
prefixes = sorted(cache)
# Loop through the rest, but only consider matching prefix/suffix pairs
for l in xrange(k*2+1, n*2+1):
for p in prefixes:
low = (p * 10**(l-k))**.5
high = ((p+1) * 10**(l-k))**.5
low = int(low / tail) * tail
high = (int(high / tail) + 1) * tail
for n in xrange(low, high, tail):
for suf in cache[p]:
x = n + suf
s = str(x*x)
if s == s[::-1]:
print x, s
Sample output:
0 0
1 1
2 4
3 9
11 121
22 484
26 676
101 10201
111 12321
121 14641
202 40804
212 44944
<snip>
111010010111 12323222344844322232321
111100001111 12343210246864201234321
111283619361 12384043938083934048321
112247658961 12599536942224963599521
128817084669 16593841302620314839561
200000000002 40000000000800000000004

Categories

Resources