Smallest number whose digits are decreasing - python

I found a problem to implement functions that takes a positive integer n as an input and returns the smallest positive integer larger than n whose digits are decreasing and similarly for a function that returns the smallest positive integer larger than n whose digits are increasing. I think the increasing function works correctly. But what is the mistake in the function decrease? For the input decreasing(100) it returns 11 rather than 110.
# the next integer whose digits are increasing.
def increasing(n):
asastring = str(n)
length = len(asastring)
if asastring == "9"*length:
return "1"*(length+1)
if length == 1:
return int(n)+1
if length >= 2:
firstcharacter = asastring[0]
secondcharacter = asastring[1]
if int(firstcharacter) > int(secondcharacter):
return int(str(firstcharacter)*length)
if firstcharacter == secondcharacter:
return firstcharacter+str(increasing(int(asastring[1:])))
if int(firstcharacter) < int(secondcharacter):
if secondcharacter == "9":
return str(int(firstcharacter)+1) * len(str(n))
return firstcharacter+str(increasing(int(asastring[1:])))
# the next integer whose digits are decreasing.
def decreasing(n):
asastring = str(n)
length = len(asastring)
# First the case where we need to add a digit.
if asastring == "9"*length:
return "1"+"0"*length
# Now we know that the next integer has the same number of digits as the original number.
if length == 1:
return int(n)+1
if length >= 2:
firstcharacter = asastring[0]
secondcharacter = asastring[1]
if int(firstcharacter) > int(secondcharacter):
endpart = str(((asastring[1:3])))
value = firstcharacter + str(decreasing(int(asastring[1:])))
return str(firstcharacter) + str(decreasing(int(asastring[1:])))
if int(firstcharacter) == int(secondcharacter):
return decreasing(firstcharacter+str(decreasing(int(asastring[1:]))))
if int(firstcharacter) < int(secondcharacter):
return str(int(firstcharacter)+1)+'0'*(length-1)
i=100
print(increasing(i))
print(decreasing(i))

You need to remove the int type casting done in the recursive calls as int('00') is converting your number to zero(basically removing all starting zeros) and shortening the length of your string. Just remove that casting.. remaining code is working fine:
def decreasing(n):
asastring = str(n)
length = len(asastring)
# First the case where we need to add a digit.
if asastring == "9"*length:
return "1"+"0"*length
# Now we know that the next integer has the same number of digits as the original number.
if length == 1:
return int(n)+1
if length >= 2:
firstcharacter = asastring[0]
secondcharacter = asastring[1]
if int(firstcharacter) > int(secondcharacter):
return str(firstcharacter) + str(decreasing(asastring[1:]))
if int(firstcharacter) == int(secondcharacter):
return decreasing(firstcharacter+str(decreasing(asastring[1:])))
if int(firstcharacter) < int(secondcharacter):
return str(int(firstcharacter)+1)+'0'*(length-1)

There are multiple intertwined issues that need to be addressed. The naming of these two functions is a source of confusion. If we follow the logic, then the function increasing() should be called nondecreasing() and similarly, the function decreasing() should be called nonincreasing(). It's the difference between > (greater than) and >= (greater than or equal).
The next confusion is what type do these functions accept and return? If we examine what the working increasing() function returns, we get:
str return "1"*(length+1)
int return int(n)+1
int return int(str(firstcharacter)*length)
str return firstcharacter+str(increasing(int(asastring[1:])))
str return str(int(firstcharacter)+1) * len(str(n))
str return firstcharacter+str(increasing(int(asastring[1:])))
If we similarly look at how the increasing() deals with its own internal recursive calls to see what it thinks it accepts and returns, we get:
int -> int return firstcharacter+str(increasing(int(asastring[1:])))
int -> int return firstcharacter+str(increasing(int(asastring[1:])))
So here's an attempted rework of increasing(), aka nondecreasing(), that tries to make it consistently accept an int and return an int:
def nondecreasing(n): # aka increasing()
as_string = str(n)
length = len(as_string)
if as_string == "9" * length:
return int("1" * (length + 1))
if length == 1:
return int(n) + 1
first_digit, second_digit, second_digit_onward = as_string[0], as_string[1], as_string[1:]
if first_digit > second_digit:
return int(first_digit * length)
if first_digit == second_digit:
return int(first_digit + str(nondecreasing(int(second_digit_onward))))
if as_string == first_digit + "9" * (length - 1):
return int(str(int(first_digit) + 1) * length)
return int(first_digit + str(nondecreasing(int(second_digit_onward))))
The decreasing(), aka nonincreasing(), function is more problematic. It relies on its ability to accept an int, or a str upon internal calls, to solve the problem.
Discussing these sort of issues, and not making other programmers rediscover them, are what code comments are all about.
I don't believe the above issue precludes nonincreasing() from consistently returning an int:
def nonincreasing(n): # aka decreasing()
as_string = str(n)
length = len(as_string)
if as_string == "9" * length:
return int("1" + "0" * length)
if length == 1:
return int(n) + 1
first_digit, second_digit, second_digit_onward = as_string[0], as_string[1], as_string[1:]
if first_digit > second_digit:
return int(first_digit + str(nonincreasing(second_digit_onward)))
if first_digit == second_digit:
remaining_digits = str(nonincreasing(second_digit_onward))
second_digit = remaining_digits[0]
n = first_digit + remaining_digits
if first_digit < second_digit:
return int(str(int(first_digit) + 1) + '0' * (length - 1))
return int(n)
The key to fixing this function was to remove the return statement from the penultimate if clause and instead fix up the data and let it fall through to the next if clause to see if the results need repair or not.
I believe #devender22's insight about int() casting is a crucial one but I don't believe the accompanying solution is valid as it generates large blocks of incorrect results (e.g. 990 through 998 all go to 1000 when they should simply be bumped up by 1).
In order to check my nonincreasing() function with all of its cases, I wrote a less efficient, non-recursive solution, without separate cases, using completely different Python operators:
def nonincreasing(n):
def is_increasing(n):
string = str(n)
return any(map(lambda x, y: y > x, string, string[1:]))
while is_increasing(n + 1):
n += 1
return n + 1
And then made sure the two implementations agreed on their output.

Related

Python problem creating recursion function

I'm trying to create a function that
The input of it will be a digit.
And the length of the wanted result
The output will be the digit in the length of user input
For example doMul(3,6) will output: 333333.
Now I tried to do this:
def doMul(digit, count=1):
if count == 0:
return 1
return digit + digit * (10 ** doMul(digit, count - 1))
But it doesn't seem to work.
And I can't figure out why.
Worth mentioning I don't want to use any strings.
y ** x is actually y in power of x, not multiplication. You should remove it and return digit rather than 1
def doMul(digit, count=1):
if count == 1:
return digit
return digit + 10 * doMul(digit, count - 1)
def doMul(n, m):
"Return the decimal number that is nnn... m times."
return n * ((10**m)-1) // 9
The reason this works is that M copies of N is simply M copies of 1, multiplied by N. And since (10 ** M) - 1 is the same as doMul(9, m), we can easily generate our base number.
If you absolutely need a recursive solution:
def doMul(n, m):
if m <= 1:
return n
return n + 10 * doMul(n, m-1)
This does essentially the same, compute one digit less than we want, multiply it by 10, then add the digit we want.
Does this work for you?
def doMul(digit, count=1):
if count == 1:
return digit
return str(digit) + str(doMul(digit, count-1))
print(doMul(3, 6))

place a decimal point function in python

I am looking to write a function in python that places a decimal point into some string.
for example if the string I give is '12355' and then I put the point place in 2
the output should skip the first two numbers and show '12.355'
please help,
thank you
Here
place = 3
number = "12345"
result = number[:place] + "." + number[place:]
print(result)
The result will have the decimal point 3 characters from the first one.
When I run it the output is
123.45
If you were to do a function, then
def insert_decimal(position,number):
return number[:position] + "." + number[position:]
You can use string indexing, as if it were a list:
def insert_decimal_point(number, position):
return number[:position] + "." + number[position:]
def add_decimal_point(s, n):
return f'{s[:n]}.{s[n:]}' if 0 < n < len(s) else s
add_decimal_point("23567", 2)
23.567
If n is greater or equal to the length of the string or if it is negative, the original string is returned:
add_decimal_point("23567", 10)
23567
Or you can treat this string mathematically as a number:
s = "12355"
n = float(s)
length = len(s)
place = 2
power = length - place
print(n / (10 ** power))
lets separate logic into the function:
def decimal_point(s, place):
n = float(s)
length = len(s)
power = length - place
return n / (10 ** power)

How to convert a number to base 11 in python? [duplicate]

Python allows easy creation of an integer from a string of a given base via
int(str, base).
I want to perform the inverse: creation of a string from an integer,
i.e. I want some function int2base(num, base), such that:
int(int2base(x, b), b) == x
The function name/argument order is unimportant.
For any number x and base b that int() will accept.
This is an easy function to write: in fact it's easier than describing it in this question. However, I feel like I must be missing something.
I know about the functions bin, oct, hex, but I cannot use them for a few reasons:
Those functions are not available on older versions of Python, with which I need compatibility with (2.2)
I want a general solution that can be called the same way for different bases
I want to allow bases other than 2, 8, 16
Related
Python elegant inverse function of int(string, base)
Integer to base-x system using recursion in python
Base 62 conversion in Python
How to convert an integer to the shortest url-safe string in Python?
Surprisingly, people were giving only solutions that convert to small bases (smaller than the length of the English alphabet). There was no attempt to give a solution which converts to any arbitrary base from 2 to infinity.
So here is a super simple solution:
def numberToBase(n, b):
if n == 0:
return [0]
digits = []
while n:
digits.append(int(n % b))
n //= b
return digits[::-1]
so if you need to convert some super huge number to the base 577,
numberToBase(67854 ** 15 - 102, 577), will give you a correct solution:
[4, 473, 131, 96, 431, 285, 524, 486, 28, 23, 16, 82, 292, 538, 149, 25, 41, 483, 100, 517, 131, 28, 0, 435, 197, 264, 455],
Which you can later convert to any base you want
at some point of time you will notice that sometimes there is no built-in library function to do things that you want, so you need to write your own. If you disagree, post you own solution with a built-in function which can convert a base 10 number to base 577.
this is due to lack of understanding what a number in some base means.
I encourage you to think for a little bit why base in your method works only for n <= 36. Once you are done, it will be obvious why my function returns a list and has the signature it has.
If you need compatibility with ancient versions of Python, you can either use gmpy (which does include a fast, completely general int-to-string conversion function, and can be built for such ancient versions – you may need to try older releases since the recent ones have not been tested for venerable Python and GMP releases, only somewhat recent ones), or, for less speed but more convenience, use Python code – e.g., for Python 2, most simply:
import string
digs = string.digits + string.ascii_letters
def int2base(x, base):
if x < 0:
sign = -1
elif x == 0:
return digs[0]
else:
sign = 1
x *= sign
digits = []
while x:
digits.append(digs[int(x % base)])
x = int(x / base)
if sign < 0:
digits.append('-')
digits.reverse()
return ''.join(digits)
For Python 3, int(x / base) leads to incorrect results, and must be changed to x // base:
import string
digs = string.digits + string.ascii_letters
def int2base(x, base):
if x < 0:
sign = -1
elif x == 0:
return digs[0]
else:
sign = 1
x *= sign
digits = []
while x:
digits.append(digs[x % base])
x = x // base
if sign < 0:
digits.append('-')
digits.reverse()
return ''.join(digits)
"{0:b}".format(100) # bin: 1100100
"{0:x}".format(100) # hex: 64
"{0:o}".format(100) # oct: 144
def baseN(num,b,numerals="0123456789abcdefghijklmnopqrstuvwxyz"):
return ((num == 0) and numerals[0]) or (baseN(num // b, b, numerals).lstrip(numerals[0]) + numerals[num % b])
ref:
http://code.activestate.com/recipes/65212/
Please be aware that this may lead to
RuntimeError: maximum recursion depth exceeded in cmp
for very big integers.
>>> numpy.base_repr(10, base=3)
'101'
Note that numpy.base_repr() has a limit of 36 as its base. Otherwise it throws a ValueError
Recursive
I would simplify the most voted answer to:
BS="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
def to_base(n, b):
return "0" if not n else to_base(n//b, b).lstrip("0") + BS[n%b]
With the same advice for RuntimeError: maximum recursion depth exceeded in cmp on very large integers and negative numbers. (You could usesys.setrecursionlimit(new_limit))
Iterative
To avoid recursion problems:
BS="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
def to_base(s, b):
res = ""
while s:
res+=BS[s%b]
s//= b
return res[::-1] or "0"
Great answers!
I guess the answer to my question was "no" I was not missing some obvious solution.
Here is the function I will use that condenses the good ideas expressed in the answers.
allow caller-supplied mapping of characters (allows base64 encode)
checks for negative and zero
maps complex numbers into tuples of strings
def int2base(x,b,alphabet='0123456789abcdefghijklmnopqrstuvwxyz'):
'convert an integer to its string representation in a given base'
if b<2 or b>len(alphabet):
if b==64: # assume base64 rather than raise error
alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
else:
raise AssertionError("int2base base out of range")
if isinstance(x,complex): # return a tuple
return ( int2base(x.real,b,alphabet) , int2base(x.imag,b,alphabet) )
if x<=0:
if x==0:
return alphabet[0]
else:
return '-' + int2base(-x,b,alphabet)
# else x is non-negative real
rets=''
while x>0:
x,idx = divmod(x,b)
rets = alphabet[idx] + rets
return rets
You could use baseconv.py from my project: https://github.com/semente/python-baseconv
Sample usage:
>>> from baseconv import BaseConverter
>>> base20 = BaseConverter('0123456789abcdefghij')
>>> base20.encode(1234)
'31e'
>>> base20.decode('31e')
'1234'
>>> base20.encode(-1234)
'-31e'
>>> base20.decode('-31e')
'-1234'
>>> base11 = BaseConverter('0123456789-', sign='$')
>>> base11.encode('$1234')
'$-22'
>>> base11.decode('$-22')
'$1234'
There is some bultin converters as for example baseconv.base2, baseconv.base16 and baseconv.base64.
def base(decimal ,base) :
list = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
other_base = ""
while decimal != 0 :
other_base = list[decimal % base] + other_base
decimal = decimal / base
if other_base == "":
other_base = "0"
return other_base
print base(31 ,16)
output:
"1F"
def base_conversion(num, base):
digits = []
while num > 0:
num, remainder = divmod(num, base)
digits.append(remainder)
return digits[::-1]
http://code.activestate.com/recipes/65212/
def base10toN(num,n):
"""Change a to a base-n number.
Up to base-36 is supported without special notation."""
num_rep={10:'a',
11:'b',
12:'c',
13:'d',
14:'e',
15:'f',
16:'g',
17:'h',
18:'i',
19:'j',
20:'k',
21:'l',
22:'m',
23:'n',
24:'o',
25:'p',
26:'q',
27:'r',
28:'s',
29:'t',
30:'u',
31:'v',
32:'w',
33:'x',
34:'y',
35:'z'}
new_num_string=''
current=num
while current!=0:
remainder=current%n
if 36>remainder>9:
remainder_string=num_rep[remainder]
elif remainder>=36:
remainder_string='('+str(remainder)+')'
else:
remainder_string=str(remainder)
new_num_string=remainder_string+new_num_string
current=current/n
return new_num_string
Here's another one from the same link
def baseconvert(n, base):
"""convert positive decimal integer n to equivalent in another base (2-36)"""
digits = "0123456789abcdefghijklmnopqrstuvwxyz"
try:
n = int(n)
base = int(base)
except:
return ""
if n < 0 or base < 2 or base > 36:
return ""
s = ""
while 1:
r = n % base
s = digits[r] + s
n = n / base
if n == 0:
break
return s
I made a pip package for this.
I recommend you use my bases.py https://github.com/kamijoutouma/bases.py which was inspired by bases.js
from bases import Bases
bases = Bases()
bases.toBase16(200) // => 'c8'
bases.toBase(200, 16) // => 'c8'
bases.toBase62(99999) // => 'q0T'
bases.toBase(200, 62) // => 'q0T'
bases.toAlphabet(300, 'aAbBcC') // => 'Abba'
bases.fromBase16('c8') // => 200
bases.fromBase('c8', 16) // => 200
bases.fromBase62('q0T') // => 99999
bases.fromBase('q0T', 62) // => 99999
bases.fromAlphabet('Abba', 'aAbBcC') // => 300
refer to https://github.com/kamijoutouma/bases.py#known-basesalphabets
for what bases are usable
EDIT:
pip link https://pypi.python.org/pypi/bases.py/0.2.2
def int2base(a, base, numerals="0123456789abcdefghijklmnopqrstuvwxyz"):
baseit = lambda a=a, b=base: (not a) and numerals[0] or baseit(a-a%b,b*base)+numerals[a%b%(base-1) or (a%b) and (base-1)]
return baseit()
explanation
In any base every number is equal to a1+a2*base**2+a3*base**3... The "mission" is to find all a 's.
For everyN=1,2,3... the code is isolating the aN*base**N by "mouduling" by b for b=base**(N+1) which slice all a 's bigger than N, and slicing all the a 's that their serial is smaller than N by decreasing a everytime the func is called by the current aN*base**N .
Base%(base-1)==1 therefor base**p%(base-1)==1 and therefor q*base^p%(base-1)==q with only one exception when q=base-1 which returns 0.
To fix that in case it returns 0 the func is checking is it 0 from the beggining.
advantages
in this sample theres only one multiplications (instead of division) and some moudulueses which relatively takes small amounts of time.
While the currently top answer is definitely an awesome solution, there remains more customization users might like.
Basencode adds some of these features, including conversions of floating point numbers, modifying digits (in the linked answer, only numbers can be used).
Here's a possible use case:
>>> from basencode import *
>>> n1 = Number(12345)
>> n1.repr_in_base(64) # convert to base 64
'30V'
>>> Number('30V', 64) # construct Integer from base 64
Integer(12345)
>>> n1.repr_in_base(8)
'30071'
>>> n1.repr_in_octal() # shortcuts
'30071'
>>> n1.repr_in_bin() # equivelant to `n1.repr_in_base(2)`
'11000000111001'
>>> n1.repr_in_base(2, digits=list('-+')) # override default digits: use `-` and `+` in place of `0` and `1`
'++------+++--+'
>>> n1.repr_in_base(33) # yet another base - all bases from 2 to 64 are supported from the start
'bb3'
How would you add any bases you want? Let me replicate the example of the currently most upvoted answer: the digits parameter allows you to override the default digits from base 2 to 64, and provide digits for any base higher than that. The mode parameter determines how the value of the representation will determine how (list or string) the answer will be returned.
>>> n2 = Number(67854 ** 15 - 102)
>>> n2.repr_in_base(577, digits=[str(i) for i in range(577)], mode="l")
['4', '473', '131', '96', '431', '285', '524', '486', '28', '23', '16', '82', '292', '538', '149', '25', '41', '483', '100', '517', '131', '28', '0', '435', '197', '264', '455']
>>> n2.repr_in_base(577, mode="l") # the program remembers the digits for base 577 now
['4', '473', '131', '96', '431', '285', '524', '486', '28', '23', '16', '82', '292', '538', '149', '25', '41', '483', '100', '517', '131', '28', '0', '435', '197', '264', '455']
Operations can be done: the Number class returns an instance of basencode.Integer if the provided number is an Integer, else it returns a basencode.Float
>>> n3 = Number(54321) # the Number class returns an instance of `basencode.Integer` if the provided number is an Integer, otherwise it returns a `basencode.Float`.
>>> n1 + n3
Integer(66666)
>>> n3 - n1
Integer(41976)
>>> n1 * n3
Integer(670592745)
>>> n3 // n1
Integer(4)
>>> n3 / n1 # a basencode.Float class allows conversion of floating point numbers
Float(4.400243013365735)
>>> (n3 / n1).repr_in_base(32)
'4.cpr56v6rnc4oitoblha2r11sus0dheqd4pgechfcjklo74b2bgom7j8ih86mipdvss0068sehi9f3791mdo4uotfujq66cf0jkgo'
>>> n4 = Number(0.5) # returns a basencode.Float
>>> n4.repr_in_bin() # binary version of 0.5
'0.1'
Disclaimer: this project is under active maintenance, and I'm a contributor.
>>> import string
>>> def int2base(integer, base):
if not integer: return '0'
sign = 1 if integer > 0 else -1
alphanum = string.digits + string.ascii_lowercase
nums = alphanum[:base]
res = ''
integer *= sign
while integer:
integer, mod = divmod(integer, base)
res += nums[mod]
return ('' if sign == 1 else '-') + res[::-1]
>>> int2base(-15645, 23)
'-16d5'
>>> int2base(213, 21)
'a3'
A recursive solution for those interested. Of course, this will not work with negative binary values. You would need to implement Two's Complement.
def generateBase36Alphabet():
return ''.join([str(i) for i in range(10)]+[chr(i+65) for i in range(26)])
def generateAlphabet(base):
return generateBase36Alphabet()[:base]
def intToStr(n, base, alphabet):
def toStr(n, base, alphabet):
return alphabet[n] if n < base else toStr(n//base,base,alphabet) + alphabet[n%base]
return ('-' if n < 0 else '') + toStr(abs(n), base, alphabet)
print('{} -> {}'.format(-31, intToStr(-31, 16, generateAlphabet(16)))) # -31 -> -1F
def base_changer(number,base):
buff=97+abs(base-10)
dic={};buff2='';buff3=10
for i in range(97,buff+1):
dic[buff3]=chr(i)
buff3+=1
while(number>=base):
mod=int(number%base)
number=int(number//base)
if (mod) in dic.keys():
buff2+=dic[mod]
continue
buff2+=str(mod)
if (number) in dic.keys():
buff2+=dic[number]
else:
buff2+=str(number)
return buff2[::-1]
Here is an example of how to convert a number of any base to another base.
from collections import namedtuple
Test = namedtuple("Test", ["n", "from_base", "to_base", "expected"])
def convert(n: int, from_base: int, to_base: int) -> int:
digits = []
while n:
(n, r) = divmod(n, to_base)
digits.append(r)
return sum(from_base ** i * v for i, v in enumerate(digits))
if __name__ == "__main__":
tests = [
Test(32, 16, 10, 50),
Test(32, 20, 10, 62),
Test(1010, 2, 10, 10),
Test(8, 10, 8, 10),
Test(150, 100, 1000, 150),
Test(1500, 100, 10, 1050000),
]
for test in tests:
result = convert(*test[:-1])
assert result == test.expected, f"{test=}, {result=}"
print("PASSED!!!")
Say we want to convert 14 to base 2. We repeatedly apply the division algorithm until the quotient is 0:
14 = 2 x 7
7 = 2 x 3 + 1
3 = 2 x 1 + 1
1 = 2 x 0 + 1
The binary representation is just the remainder read from bottom to top. This can be proved by expanding
14 = 2 x 7 = 2 x (2 x 3 + 1) = 2 x (2 x (2 x 1 + 1) + 1) = 2 x (2 x (2 x (2 x 0 + 1) + 1) + 1) = 2^3 + 2^2 + 2
The code is the implementation of the above algorithm.
def toBaseX(n, X):
strbin = ""
while n != 0:
strbin += str(n % X)
n = n // X
return strbin[::-1]
This is my approach. At first converting the number then casting it to string.
def to_base(n, base):
if base == 10:
return n
result = 0
counter = 0
while n:
r = n % base
n //= base
result += r * 10**counter
counter+=1
return str(result)
I have written this function which I use to encode in different bases. I also provided the way to shift the result by a value 'offset'. This is useful if you'd like to encode to bases above 64, but keeping displayable chars (like a base 95).
I also tried to avoid reversing the output 'list' and tried to minimize computing operations. The array of pow(base) is computed on demand and kept for additional calls to the function.
The output is a binary string
pows = {}
######################################################
def encode_base(value,
base = 10,
offset = 0) :
"""
Encode value into a binary string, according to the desired base.
Input :
value : Any positive integer value
offset : Shift the encoding (eg : Starting at chr(32))
base : The base in which we'd like to encode the value
Return : Binary string
Example : with : offset = 32, base = 64
100 -> !D
200 -> #(
"""
# Determine the number of loops
try :
pb = pows[base]
except KeyError :
pb = pows[base] = {n : base ** n for n in range(0, 8) if n < 2 ** 48 -1}
for n in pb :
if value < pb[n] :
n -= 1
break
out = []
while n + 1 :
b = pb[n]
out.append(chr(offset + value // b))
n -= 1
value %= b
return ''.join(out).encode()
This function converts any integer from any base to any base
def baseconvert(number, srcbase, destbase):
if srcbase != 10:
sum = 0
for _ in range(len(str(number))):
sum += int(str(number)[_]) * pow(srcbase, len(str(number)) - _ - 1)
b10 = sum
return baseconvert(b10, 10, destbase)
end = ''
q = number
while(True):
r = q % destbase
q = q // destbase
end = str(r) + end
if(q<destbase):
end = str(q) + end
return int(end)
The below provided Python code converts a Python integer to a string in arbitrary base ( from 2 up to infinity ) and works in both directions. So all the created strings can be converted back to Python integers by providing a string for N instead of an integer.
The code works only on positive numbers by intention (there is in my eyes some hassle about negative values and their bit representations I don't want to dig into). Just pick from this code what you need, want or like, or just have fun learning about available options. Much is there only for the purpose of documenting all the various available approaches ( e.g. the Oneliner seems not to be fast, even if promised to be ).
I like the by Salvador Dali proposed format for infinite large bases. A nice proposal which works optically well even for simple binary bit representations. Notice that the width=x padding parameter in case of infiniteBase=True formatted string applies to the digits and not to the whole number. It seems, that code handling infiniteBase digits format runs even a bit faster than the other options - another reason for using it?
I don't like the idea of using Unicode for extending the number of symbols available for digits, so don't look in the code below for it, because it's not there. Use the proposed infiniteBase format instead or store integers as bytes for compression purposes.
def inumToStr( N, base=2, width=1, infiniteBase=False,\
useNumpy=False, useRecursion=False, useOneliner=False, \
useGmpy=False, verbose=True):
''' Positive numbers only, but works in BOTH directions.
For strings in infiniteBase notation set for bases <= 62
infiniteBase=True . Examples of use:
inumToStr( 17, 2, 1, 1) # [1,0,0,0,1]
inumToStr( 17, 3, 5) # 00122
inumToStr(245, 16, 4) # 00F5
inumToStr(245, 36, 4,0,1) # 006T
inumToStr(245245245245,36,10,0,1) # 0034NWOQBH
inumToStr(245245245245,62) # 4JhA3Th
245245245245 == int(gmpy2.mpz('4JhA3Th',62))
inumToStr(245245245245,99,2) # [25,78, 5,23,70,44]
----------------------------------------------------
inumToStr( '[1,0,0,0,1]',2, infiniteBase=True ) # 17
inumToStr( '[25,78, 5,23,70,44]', 99) # 245245245245
inumToStr( '0034NWOQBH', 36 ) # 245245245245
inumToStr( '4JhA3Th' , 62 ) # 245245245245
----------------------------------------------------
--- Timings for N = 2**4096, base=36:
standard: 0.0023
infinite: 0.0017
numpy : 0.1277
recursio; 0.0022
oneliner: 0.0146
For N = 2**8192:
standard: 0.0075
infinite: 0.0053
numpy : 0.1369
max. recursion depth exceeded: recursio/oneliner
'''
show = print
if type(N) is str and ( infiniteBase is True or base > 62 ):
lstN = eval(N)
if verbose: show(' converting a non-standard infiniteBase bits string to Python integer')
return sum( [ item*base**pow for pow, item in enumerate(lstN[::-1]) ] )
if type(N) is str and base <= 36:
if verbose: show('base <= 36. Returning Python int(N, base)')
return int(N, base)
if type(N) is str and base <= 62:
if useGmpy:
if verbose: show(' base <= 62, useGmpy=True, returning int(gmpy2.mpz(N,base))')
return int(gmpy2.mpz(N,base))
else:
if verbose: show(' base <= 62, useGmpy=False, self-calculating return value)')
lstStrOfDigits="0123456789"+ \
"abcdefghijklmnopqrstuvwxyz".upper() + \
"abcdefghijklmnopqrstuvwxyz"
dictCharToPow = {}
for index, char in enumerate(lstStrOfDigits):
dictCharToPow.update({char : index})
return sum( dictCharToPow[item]*base**pow for pow, item in enumerate(N[::-1]) )
#:if
#:if
if useOneliner and base <= 36:
if verbose: show(' base <= 36, useOneliner=True, running the Oneliner code')
d="0123456789abcdefghijklmnopqrstuvwxyz"
baseit = lambda a=N, b=base: (not a) and d[0] or \
baseit(a-a%b,b*base)+d[a%b%(base-1) or (a%b) and (base-1)]
return baseit().rjust(width, d[0])[1:]
if useRecursion and base <= 36:
if verbose: show(' base <= 36, useRecursion=True, running recursion algorythm')
BS="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
def to_base(n, b):
return "0" if not n else to_base(n//b, b).lstrip("0") + BS[n%b]
return to_base(N, base).rjust(width,BS[0])
if base > 62 or infiniteBase:
if verbose: show(' base > 62 or infiniteBase=True, returning a non-standard digits string')
# Allows arbitrary large base with 'width=...'
# applied to each digit (useful also for bits )
N, digit = divmod(N, base)
strN = str(digit).rjust(width, ' ')+']'
while N:
N, digit = divmod(N, base)
strN = str(digit).rjust(width, ' ') + ',' + strN
return '[' + strN
#:if
if base == 2:
if verbose: show(" base = 2, returning Python str(f'{N:0{width}b}')")
return str(f'{N:0{width}b}')
if base == 8:
if verbose: show(" base = 8, returning Python str(f'{N:0{width}o}')")
return str(f'{N:0{width}o}')
if base == 16:
if verbose: show(" base = 16, returning Python str(f'{N:0{width}X}')")
return str(f'{N:0{width}X}')
if base <= 36:
if useNumpy:
if verbose: show(" base <= 36, useNumpy=True, returning np.base_repr(N, base)")
import numpy as np
strN = np.base_repr(N, base)
return strN.rjust(width, '0')
else:
if verbose: show(' base <= 36, useNumpy=False, self-calculating return value)')
lstStrOfDigits="0123456789"+"abcdefghijklmnopqrstuvwxyz".upper()
strN = lstStrOfDigits[N % base] # rightmost digit
while N >= base:
N //= base # consume already converted digit
strN = lstStrOfDigits[N % base] + strN # add digits to the left
#:while
return strN.rjust(width, lstStrOfDigits[0])
#:if
#:if
if base <= 62:
if useGmpy:
if verbose: show(" base <= 62, useGmpy=True, returning gmpy2.digits(N, base)")
import gmpy2
strN = gmpy2.digits(N, base)
return strN.rjust(width, '0')
# back to Python int from gmpy2.mpz with
# int(gmpy2.mpz('4JhA3Th',62))
else:
if verbose: show(' base <= 62, useGmpy=False, self-calculating return value)')
lstStrOfDigits= "0123456789" + \
"abcdefghijklmnopqrstuvwxyz".upper() + \
"abcdefghijklmnopqrstuvwxyz"
strN = lstStrOfDigits[N % base] # rightmost digit
while N >= base:
N //= base # consume already converted digit
strN = lstStrOfDigits[N % base] + strN # add digits to the left
#:while
return strN.rjust(width, lstStrOfDigits[0])
#:if
#:if
#:def
I'm presenting a "unoptimized" solution for bases between 2 and 9:
def to_base(N, base=2):
N_in_base = ''
while True:
N_in_base = str(N % base) + N_in_base
N //= base
if N == 0:
break
return N_in_base
This solution does not require reversing the final result, but it's actually not optimized. Refer to this answer to see why: https://stackoverflow.com/a/37133870/7896998
Simple base transformation
def int_to_str(x, b):
s = ""
while x:
s = str(x % b) + s
x //= b
return s
Example of output with no 0 to base 9
s = ""
x = int(input())
while x:
if x % 9 == 0:
s = "9" + s
x -= x % 10
x = x // 9
else:
s = str(x % 9) + s
x = x // 9
print(s)
def dec_to_radix(input, to_radix=2, power=None):
if not isinstance(input, int):
raise TypeError('Not an integer!')
elif power is None:
power = 1
if input == 0:
return 0
else:
remainder = input % to_radix**power
digit = str(int(remainder/to_radix**(power-1)))
return int(str(dec_to_radix(input-remainder, to_radix, power+1)) + digit)
def radix_to_dec(input, from_radix):
if not isinstance(input, int):
raise TypeError('Not an integer!')
return sum(int(digit)*(from_radix**power) for power, digit in enumerate(str(input)[::-1]))
def radix_to_radix(input, from_radix=10, to_radix=2, power=None):
dec = radix_to_dec(input, from_radix)
return dec_to_radix(dec, to_radix, power)
Another short one (and easier to understand imo):
def int_to_str(n, b, symbols='0123456789abcdefghijklmnopqrstuvwxyz'):
return (int_to_str(n/b, b, symbols) if n >= b else "") + symbols[n%b]
And with proper exception handling:
def int_to_str(n, b, symbols='0123456789abcdefghijklmnopqrstuvwxyz'):
try:
return (int_to_str(n/b, b) if n >= b else "") + symbols[n%b]
except IndexError:
raise ValueError(
"The symbols provided are not enough to represent this number in "
"this base")
Here is a recursive version that handles signed integers and custom digits.
import string
def base_convert(x, base, digits=None):
"""Convert integer `x` from base 10 to base `base` using `digits` characters as digits.
If `digits` is omitted, it will use decimal digits + lowercase letters + uppercase letters.
"""
digits = digits or (string.digits + string.ascii_letters)
assert 2 <= base <= len(digits), "Unsupported base: {}".format(base)
if x == 0:
return digits[0]
sign = '-' if x < 0 else ''
x = abs(x)
first_digits = base_convert(x // base, base, digits).lstrip(digits[0])
return sign + first_digits + digits[x % base]
Strings aren't the only choice for representing numbers: you can use a list of integers to represent the order of each digit. Those can easily be converted to a string.
None of the answers reject base < 2; and most will run very slowly or crash with stack overflows for very large numbers (such as 56789 ** 43210). To avoid such failures, reduce quickly like this:
def n_to_base(n, b):
if b < 2: raise # invalid base
if abs(n) < b: return [n]
ret = [y for d in n_to_base(n, b*b) for y in divmod(d, b)]
return ret[1:] if ret[0] == 0 else ret # remove leading zeros
def base_to_n(v, b):
h = len(v) // 2
if h == 0: return v[0]
return base_to_n(v[:-h], b) * (b**h) + base_to_n(v[-h:], b)
assert ''.join(['0123456789'[x] for x in n_to_base(56789**43210,10)])==str(56789**43210)
Speedwise, n_to_base is comparable with str for large numbers (about 0.3s on my machine), but if you compare against hex you may be surprised (about 0.3ms on my machine, or 1000x faster). The reason is because the large integer is stored in memory in base 256 (bytes). Each byte can simply be converted to a two-character hex string. This alignment only happens for bases that are powers of two, which is why there are special cases for 2,8, and 16 (and base64, ascii, utf16, utf32).
Consider the last digit of a decimal string. How does it relate to the sequence of bytes that forms its integer? Let's label the bytes s[i] with s[0] being the least significant (little endian). Then the last digit is sum([s[i]*(256**i) % 10 for i in range(n)]). Well, it happens that 256**i ends with a 6 for i > 0 (6*6=36) so that last digit is (s[0]*5 + sum(s)*6)%10. From this, you can see that the last digit depends on the sum of all the bytes. This nonlocal property is what makes converting to decimal harder.
def baseConverter(x, b):
s = ""
d = string.printable.upper()
while x > 0:
s += d[x%b]
x = x / b
return s[::-1]

Returns the largest n such that R[n] = S

Write a function answer(str_S) which, given the base-10 string
representation of an integer S, returns the largest n such that R(n) =
S. Return the answer as a string in base-10 representation. If there
is no such n, return "None". S will be a positive integer no greater
than 10^25.
where R(n) is the number of zombits at time n:
R(0) = 1
R(1) = 1
R(2) = 2
R(2n) = R(n) + R(n + 1) + n (for n > 1)
R(2n + 1) = R(n - 1) + R(n) + 1 (for n >= 1)
Test cases
==========
Inputs:
(string) str_S = "7"
Output:
(string) "4"
Inputs:
(string) str_S = "100"
Output:
(string) "None"
My program below is correct but it is not scalable since here the range of S can be a very large number like 10^24. Could anyone help me with some suggestion to improve the code further so that it can cover any input case.
def answer(str_S):
d = {0: 1, 1: 1, 2: 2}
str_S = int(str_S)
i = 1
while True:
if i > 1:
d[i*2] = d[i] + d[i+1] + i
if d[i*2] == str_S:
return i*2
elif d[i*2] > str_S:
return None
if i>=1:
d[i*2+1] = d[i-1] + d[i] + 1
if d[i*2+1] == str_S:
return i*2 + 1
elif d[i*2+1] > str_S:
return None
i += 1
print answer('7')
First of all, where are you having trouble with the scaling? I ran your code on a 30-digit number, and it seemed to complete okay. Do you have a memory limit? Python handles arbitrarily large integers, although very large ones get flipped into digital arithmetic mode.
Given the density of R values, I suspect that you can save space as well as time if you switch to a straight array: use the value as an array index instead of a dict key.

Using setattr() to convert strings to variables

I am creating a sigsum() function which takes the sum using an input equation and an input variable. Here's what I have so far:
def sigsum(eqn, index, lower=0, upper=None, step=1):
if type(step) is not int:
raise TypeError('step must be an integer')
elif step < 1:
raise ValueError('step must be greater than or equal to 1')
if upper is None:
upper = 1280000
if lower is None:
lower = -1280000
if (upper - lower) % step:
upper -= (upper - lower) % step
index = lower
total = 0
while True:
total += eqn
if index == upper:
break
index += step
return total
Usage of function:
print(sigsum('1/(i+5)','i'))
>>> 12.5563
My current problem is converting 'eqn' and 'index' to variables that exist inside the function local namespace. I heard around that using exec is not a good idea and that maybe setattr() might work. Can anyone help me out?
Thanks.
For eqn I suggest using a lambda function:
eqn = lambda i: 1 / (i + 5)
then index is not needed, because it is just "the variable passed to the function" (does not need a name).
Then your function becomes
def integrate(fn, start = 0, end = 128000, step = 1):
"""
Return a stepwise approximation of
the integral of fn from start to end
"""
num_steps = (end - start) // step
if num_steps < 0:
raise ValueError("bad step value")
else:
return sum(fn(start + k*step) for k in range(num_steps))
and you can run it like
res = step_integrate(eqn) # => 10.253703030104417
Note that there are many steps to this, and many of them involve very small numbers; rounding errors can become a major problem. If accuracy is important you may want to manually derive an integral,
from math import log
eqn = lambda i: 1 / (i + 5)
eqn.integral = lambda i: log(i + 5)
def integrate(fn, start = 0, end = 128000, step = 1):
"""
Return the integral of fn from start to end
If fn.integral is defined, used it;
otherwise do a stepwise approximation
"""
if hasattr(fn, "integral"):
return fn.integral(end) - fn.integral(start)
else:
num_steps = (end - start) // step
if num_steps < 0:
raise ValueError("bad step value")
else:
return sum(fn(start + k*step) for k in range(num_steps))
which again runs like
res = step_integrate(eqn) # => 10.150386692204735
(note that the stepwise approximation was about 1% too high.)
I would use a lambda function as Hugh Bothwell suggested you
would have to modify sigsum as the following
def sigsum(eqn, lower=0, upper=None, step=1):
if type(step) is not int:
raise TypeError('step must be an integer')
elif step < 1:
raise ValueError('step must be greater than or equal to 1')
if upper is None:
upper = 1280000
if lower is None:
lower = -1280000
if (upper - lower) % step:
upper -= (upper - lower) % step
index = lower
total = 0
while True:
total += eqn(index)
if index == upper:
break
index += step
return total
Usage of function:
print(sigsum(lambda i: 1/(i+5)))
>>> 12.5563
you can also define a function separatly:
def myfunction(i):
return 1/(i+5)
and pass it to sigsum
print(sigsum(myfunction))
>>> 12.5563
to be able to pass function as a parameter is called in computer language speech function as first class object. (C and java for example doesn't have it, javascript and python have)

Categories