Extract the n-th digit of a number in Sagemath - python

How is it possible to extract the n-th digit of a number in Sagemath? We have to compute the 13787th digit from pi + e in Sagemath. My approach was the following:
sage: xi = e + pi
....: var1 = xi.n(digits=13786+1)
....: var2 = xi.n(digits=13787+1)
....: var3 = ((var2-var1) * 10^13787).trunc()
....: var3
0
Which gave me 0 back, however it should be 9.

The digit is indeed 9. But the subsequent digits are also 9: this part of decimal expansion goes ...9999237... Rounding rolls these 9s to 0s, carrying 1 to a higher digit.
So you need some extra digits in order to avoid the digit you are interested in from being affected by rounding. How many depends on the number; we don't know in advance if there isn't a sequence of one billion of 9s starting from that position. Here I use 10 extra digits
xi = e + pi
n = 13787
offset = 1 + floor(log(xi, 10)) # the first significant figure is not always the first digit after decimal dot, so we account for that
extra = 10
digit = int(str(xi.n(digits = n + offset + extra))[-1 - extra])
This returns 9. I think extracting with str is more reliable than subtracting two nearly-equal numbers and hoping there won't be additional loss of precition there.
Of course, including a magic number like 10 isn't reliable. Here is a better version, which starts with 10 extra digits but then increases the number until we no longer have 00000000... as a result.
xi = e + pi
n = 13787
offset = 1 + floor(log(xi, 10))
extra = 10
while True:
digits = str(xi.n(digits = n + offset + extra))[-1 - extra:]
if digits == "0" * len(digits):
extra *= 2
else:
digit = int(digits[0])
break
print(digit)
This will loop forever if the digits keep coming as 0, and rightly so: without actually knowing what the number is we can never be sure if the ...0000000... we get is not really ...999999999942... rounded up.

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

Solving Python Riddle

Problem I am supposed to solve:
The Riddler is planning his next caper somewhere on
Pennsylvania Avenue. The address on Pennsylvania is a four-digit number with
the following properties.
All four digits are different,
The digit in the thousands place is three times the digit in the tens place,
The number is odd, and
The sum of the digits is 27.
So I made a for loop that checks each four digit integer and puts the value in a place holder (i.e. thousands, hundreds, etc.) And conditional if statements to fit the conditions. But my problem is that the IDE gives me no error when I run the code, but it does not print my statement at the end. I'm having trouble figuring out what is wrong with my code.
address = 0
thousand = 0
hundred = 0
ten = 0
one = 0
for address in range(1000,9999+1):
thousand = (address/1000)%10
hundred = (address/100)%10
ten = (address/10)%10
one = (address%10)
if (thousand != hundred) and (thousand != ten) and (thousand != one) and (hundred != ten) and (hundred != one) and (ten !=one):
if thousand == (3*ten):
if one % 2 != 0:
if thousand+hundred+ten+one == 27:
print("The address is: ",address, "Pennsylvania Ave.")
It runs but the print statement does not show up.
All four digits are different, The digit in the thousands place is three times the digit in the tens place, The number is odd, and The sum of the digits is 27.
The digit in the thousands place is three times the digit in the tens place: valid combos are 3x1x, 6x2x, 9x3x.
The sum of the digits is 27: only 9x3x is possible since 27 - (6 + 2) > 8+7, the maximum remaining digits. In fact 27 - (9 + 3) = 15. The remaining digits can be 9,6 or 8,7
All four digits are different: 9,5 is not an option. The number is either 9837 or 9738.
The number is odd: it's 9837.
Some pencil and paper works better than a for loop here.
That being said, keep in mind that / is the true division operator in Python 3, irrespective of type. So when address = 6754, for example
thousand = (address / 1000) % 10
evaluates as
thousand = 6.754 % 10
which is just 6.754, not 6 as you were probably hoping. To get 6, use the integer division operator //:
thousand = (address // 1000) % 10
Number Theory
isop = []
for a in range(1, 10, 1):
for b in range(0, 10, 1):
for c in range(0, 10, 1):
for d in range(0, 10, 1):
if a!=b and a!=c and a!=d and b!=c and b!=d and c!=d:
sum = a+b+c+d
if a==3*c and sum == 27:
num = a*1000 + b*100 + c*10 + d
if num % 2 == 1:
isop.append(num)
for i in range(len(isop)):
print(isop[i])

Python3 check digit algorithm

I'm learning to wrap my head around programming and have been given the following task:
The ISBN (International Standard Book Number) is made out of 10 digits.
z1z2z3z4z5z6z7z8z9z10
The last digit z10 is a check-digit. It's made like this: First, you create a kind of cross-sum with this formula:
s = 1 * z1 + 2 * z2 + 3 * z3 + 4 * z4 + 5 * z5 + 6 * z6 + 7 * z7 + 8 * z8 + 9 * z9
The check-digit z10 is the remainder of the integer division of s divided by 11. For the remainder 10 you write x or X. Example: For the ISBN 3826604237 you get the check-digit 7.
Calculation: 1*3+2*8+3*2+4*6+5*6+6*0+7*4+8*2+9*3 = 150
The remainder of the division of 150 and 11 is 7.
The code-solution given is as followed:
# isbn.py
number = int(input("Please enter a 9-digit number: "))
z9 = number % 10
number = number//10
z8 = number % 10
number = number//10
z7 = number % 10
number = number//10
z6 = number % 10
number = number//10
z5 = number % 10
number = number//10
z4 = number % 10
number = number//10
z3 = number % 10
number = number//10
z2 = number % 10
number = number//10
z1 = number
sum = z1+2*z2+3*z3+4*z4+5*z5+6*z6+7*z7+8*z8+9*z9
checkdigit = sum%11
print("\nCheckdigit:", checkdigit)
My question simply is: How does it work? Why do I have to calculate "number // 10" and "number % 10" and this all the time? Is there a name for this kind of algorithm, and if so, how is it called?
I'd appreciate any kind of answer for this and if it seems like the easiest thing for you and you feel like I'm wasting your time, I'm sorry. So far I understood pretty much anything I've learned thus far learning python, but this task seemed a bit hard (it was in a very early chapter of the book I'm studying on work) and I got stuck and didn't get this out of my head.
Thank you in advance and have a nice day!
The operation x % 10 is called 'modulus' and returns the remainder of the division by 10. You use it in your code to isolate the rightmost digit.
The next operation x // 10 is called 'integer division', that is, a division which returns integers only (the fractional part (if any) is cut off). Integer division by 10 on a decimal number corresponds to a rightshift by one digit so that the next digit is shifted into the rightmost place.
You repeat these 2 steps until the last digit is isolated. Then you perform the multiplications, and finally take the modulus of 11 (the remainder of the division by 11) to obtain the check digit.
This repetitive code cries for a loop. Just imagine you had to handle 100 digit numbers.
You are using % aka modulus and integer division // to get one digit a time.
It is easier to not convert the whole number into an integer and then extract the individual digits, but to process the inputted string character wise.
Throw in some input validation and you get:
while True:
# don't convert to int
# repeat until exactly 9 digits are given
number = input("Please enter a 9-digit number: ").strip()
if number.isdigit() and len(number) == 9:
break
# generator method - enumerate gives you the position and the value of each character
# i.e. for enumerate('123') you get (0,'1') then (1,'2') then (2,'3')
# the sum function adds up each given tuple but premultiplies the value with its (pos+1) as position inside strings start at 0 for the 1st character - it also
# converts each single character to its integer value
s1 = sum( (pos+1)*int(num) for pos,num in enumerate(number))
# s1 is a summed generator expression for this:
s2 = 0 # do not use sum - its a built-in functions name
for pos,num in enumerate(number):
s2 += (pos+1)*int(num)
print(s1,s2) # both are the same ;o)
checkdigit = s1%11
print("\nCheckdigit:", checkdigit)
For 382660423 you get:
150 150
Checkdigit: 7
It's began from modulo arytmetic. And module, length of ICBN and coefficients is just agreement, cause coefficients has no matter (by modulo arytmetic properties (if x mod y = 0, than k * x mod y = 0, where k is integer)).

Convert fraction to string with repeating decimal places in brackets

I want to write a function in Python 3 that converts fractions given as numerator and denominator into their string representation as decimal number, but with repeating decimal places in brackets.
An example:
convert(1, 4) should output "0.25"
convert(1, 3) should output "0.(3)" instead of "0.3333333333"
convert(7, 11) should output "0.(63)" instead of "0.6363636364"
convert(29. 12) should output "2.41(6)" instead of "2.4166666667"
My current code is at the end of the question, but it fails if there are non-repeating and repeating decimal places. Here's an example run including the debug output (commented print calls):
----> 29 / 12
5
appended 4
2
appended 1
8
index 2 ['29', 2, 8] result ['2.', '4', '(', '1']
repeating 8
['2.', '4', '(', '1', ')']
What am I doing wrong here?
My code:
def convert(numerator, denominator):
#print("---->", numerator, "/", denominator)
result = [str(numerator//denominator) + "."]
subresults = [str(numerator)]
numerator %= denominator
while numerator != 0:
#print(numerator)
numerator *= 10
result_digit, numerator = divmod(numerator, denominator)
if numerator not in subresults:
subresults.append(numerator)
result.append(str(result_digit))
#print("appended", result_digit)
else:
result.insert(subresults.index(numerator), "(")
#print("index", subresults.index(numerator), subresults, "result", result)
result.append(")")
#print("repeating", numerator)
break
#print(result)
return "".join(result)
Your code just needed some minor changes (see the comments below):
def convert(numerator, denominator):
#print("---->", numerator, "/", denominator)
result = [str(numerator//denominator) + "."]
subresults = [numerator % denominator] ### changed ###
numerator %= denominator
while numerator != 0:
#print(numerator)
numerator *= 10
result_digit, numerator = divmod(numerator, denominator)
result.append(str(result_digit)) ### moved before if-statement
if numerator not in subresults:
subresults.append(numerator)
#print("appended", result_digit)
else:
result.insert(subresults.index(numerator) + 1, "(") ### added '+ 1'
#print("index", subresults.index(numerator), subresults, "result", result)
result.append(")")
#print("repeating", numerator)
break
#print(result)
return "".join(result)
I believe what is wrong is that you should only be checking if the number of decimal places previously seen is the number of the length of the cycle and it was seen just previous to this length.
I think the best way to do this would be to use some good ol' math.
Lets try and devise a way to find the decimal representation of fractions and how to know when there will be repeating decimals.
The best way to know if a fraction will terminate (or repeat) is to look at the factorization (hard problem) of the denominator.
There are many ways to find the factorization, but what we really want to know is, does this number have a prime factor other than 2 or 5. Why? Well a decimal expansion is just some number a / 10 * b. maybe 1/2 = .5 = 5/10. 1/20 = .05 = 5/100. etc.
So the factors of 10 are 2 and 5, so we want to find out if it has any other factors other than 2 and 5. Perfect, thats easy, just keep dividing by 2 until it is not divisible by 2 anymore, than do the same with 5. Or the other way around.
First we may want to find out if it is divisible by 2 or 5 before we start doing some serious work.
def div_by_a_or_b( a, b, number):
return not ( number % a ) or not ( number % b )
Then we divide out all the fives then all the twos and check if the number is 1
def powers_of_only_2_or_5(number):
numbers_to_check = [ 2, 5 ]
for n in numbers_to_check:
while not number % n: # while it is still divisible by n
number = number // n # divide it by n
return number == 1 # if it is 1 then it was only divisble by the numbers in numbers_to_check
I made this a bit more polymorphic so you can change this around if you want to change the base. (all you need is the factors of that base, for instance in base 14 you check 2 and 7 instead of 2 and 5)
Now all thats left to do is find out what we do in the case of non-terminating/repeating fractions.
Now this is super number theory filled, so i'll leave you with the algorithm and let you decide if you want to find out more on mathforum.org or wolfram alpha
Now that we can easily tell if a fraction will terminate and if not, what will be the length of its cycle of repeating digits. Now all thats left to do is find the cycle or how many digits it will start in.
In my search for an efficient algorithm, I found this post on https://softwareengineering.stackexchange.com/ which should be helpful.
some great insight - "When a rational number m/n with (m,n)=1 is expanded, the period begins after s terms and has length t, where s and t are the smallest numbers satisfying
10^s=10^(s+t) (mod n). "
So all we need to do is find s and t:
def length_of_cycle(denominator):
mods = {}
for i in range(denominator):
key = 10**i % denominator
if key in mods:
return [ mods[key], i ]
else:
mods[ key ] = i
Let's generate the numbers of the expansion
def expasionGenerator( numerator, denominator ):
while numerator:
yield numerator // denominator
numerator = ( numerator % denominator ) * 10
Now be careful about using this as it will create an infinite loop in a repeating expansion (as it should ).
Now I think we have all the tools in place to write our function:
def the_expansion( numerator, denominator ):
# will return a list of two elements, the first is the expansion
# the second is the repeating digits afterwards
# the first element's first
integer_part = [ numerator // denominator ]
numerator %= denominator
if div_by_a_or_b( 2, 5, denominator ) and powers_of_only_2_or_5( denominator ):
return [ integer_part, [ n for n in expasionGenerator( numerator, denominator ) ][1:], [0] ]
# if it is not, then it is repeating
from itertools import islice
length_of_cycle = cycleLength( denominator )
generator = expasionGenerator( numerator*10, denominator )
# multiply by 10 since we want to skip the parts before the decimal place
list_of_expansion = [ n for n in islice(generator, length_of_cycle[0]) ]
list_of_repeating = [ n for n in islice(generator, length_of_cycle[1]) ]
return [ integer_part, list_of_expansion, list_of_repeating ]
Now all thats left is to print it, that shouldn't be too bad. I am just going to build a function first that takes a list of numbers to a string:
def listOfNumbersToString(the_list):
string = ""
for n in the_list:
string += str(n)
return string
Then create the convert function:
def convert(numerator, denominator):
expansion = the_expansion(numerator,denominator)
expansion = [ listOfNumbersToString(ex) for ex in expansion ]
return expansion[0] + "." + expansion[1] + "(" + expansion[2] + ")"
interesting read on the topic at http://thestarman.pcministry.com/ and a similar-ish question on stackoverflow
This doesn't answer your actual question ("why isn't my code working?") but maybe it will be useful to you anyway. A few months ago I wrote some code to do the same thing you're trying to do now. Here it is.
import itertools
#finds the first number in the sequence (9, 99, 999, 9999, ...) that is divisible by x.
def first_divisible_repunit(x):
assert x%2 != 0 and x%5 != 0
for i in itertools.count(1):
repunit = int("9"*i)
if repunit % x == 0:
return repunit
#return information about the decimal representation of a rational number.
def form(numerator, denominator):
shift = 0
for x in (10,2,5):
while denominator % x == 0:
denominator //= x
numerator *= (10//x)
shift += 1
base = numerator // denominator
numerator = numerator % denominator
repunit = first_divisible_repunit(denominator)
repeat_part = numerator * (repunit // denominator)
repeat_size = len(str(repunit))
decimal_part = base % (10**shift)
integer_part = base // (10**shift)
return integer_part, decimal_part, shift, repeat_part, repeat_size
def printable_form(n,d):
integer_part, decimal_part, shift, repeat_part, repeat_size = form(n,d)
s = str(integer_part)
if not (decimal_part or repeat_part):
return s
s = s + "."
if decimal_part or shift:
s = s + "{:0{}}".format(decimal_part, shift)
if repeat_part:
s = s + "({:0{}})".format(repeat_part, repeat_size)
return s
test_cases = [
(1,4),
(1,3),
(7,11),
(29, 12),
(1, 9),
(2, 3),
(9, 11),
(7, 12),
(1, 81),
(22, 7),
(11, 23),
(1,97),
(5,6),
]
for n,d in test_cases:
print("{} / {} == {}".format(n, d, printable_form(n,d)))
Result:
1 / 4 == 0.25
1 / 3 == 0.(3)
7 / 11 == 0.(63)
29 / 12 == 2.41(6)
1 / 9 == 0.(1)
2 / 3 == 0.(6)
9 / 11 == 0.(81)
7 / 12 == 0.58(3)
1 / 81 == 0.(012345679)
22 / 7 == 3.(142857)
11 / 23 == 0.(4782608695652173913043)
1 / 97 == 0.(0103092783505154639175257
73195876288659793814432989690721649484
536082474226804123711340206185567)
5 / 6 == 0.8(3)
I forget exactly how it works... I think I was trying to reverse-engineer the process for finding the fraction form of a number, given its repeating decimal, which is much easier than the other way around. For example:
x = 3.(142857)
1000000*x = 3142857.(142857)
999999*x = 1000000*x - x
999999*x = 3142857.(142857) - 3.(142857)
999999*x = 3142854
x = 3142854 / 999999
x = 22 / 7
In theory, you can use the same approach going from fraction to decimal. The primary obstacle is that it's not completely trivial to turn an arbitrary fraction into something of the form "(some number) / (some amount of nines)". If your original denominator is divisible by 2 or 5, it can't evenly divide any 9-repunit. So a lot of form's work is about removing factors that would otherwise make it impossible to divide by 999...9.
The main idea is to find out the decimal place. In order word, where to put a decimal '.'
When a number is divided by 2 or 5, there is no recurring decimal. 1/2 = 0.5, 1/5 = 0.2. Only those are not 2 or not 5. eg. 3, 7, 11. How about 6? In fact, 6 is 2x3 where recurring decimal occurs due to the factor of 3. 1/6 = 1/2 - 1/3 = non recurring part + recurring part.
Take an other example 1/56. 56=8x7=2^3x7. Note that 1/56 = 1/7 - 1/8 = 1/7 - 1/2^3. There are 2 parts. The front part is 1/7 which is recurring 0.(142857), while the latter part 1/2^3 = 0.125 not recurring. However, 1/56 = 0.017(857142). 1/7 has recurring just after the '.' The recurring part for 1/56 is 3 decimal place later. This is because 0.125 has 3 decimal place and make it not recurring until 3 decimal place later. When we know where the recurring part starts, it is not hard to use long division to find out where the recurring's last digit.
Similar case for 5. Any fraction can have form like = a/2^m + b/5^n + recurring part. The recurring part is pushed rightward either by a/2^m or b/5^n. This is not hard to find out which ones push harder. Then we know where the recurring part starts.
For finding recurring decimal, we use long division. Since long divison will get the remainder, multiply the remainder by 10 and then use as a new nomerator and divide again. This process goes on and on. If the digit appear again. This is the end of the recurring.

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. :)

Categories

Resources