Convert fraction to float? - python

Kind of like this question, but in reverse.
Given a string like 1, 1/2, or 1 2/3, what's the best way to convert it into a float? I'm thinking about using regexes on a case-by-case basis, but perhaps someone knows of a better way, or a pre-existing solution. I was hoping I could just use eval, but I think the 3rd case prevents that.

maybe something like this (2.6+)
from fractions import Fraction
float(sum(Fraction(s) for s in '1 2/3'.split()))

I tweaked James' answer a bit.
def convert_to_float(frac_str):
try:
return float(frac_str)
except ValueError:
num, denom = frac_str.split('/')
try:
leading, num = num.split(' ')
whole = float(leading)
except ValueError:
whole = 0
frac = float(num) / float(denom)
return whole - frac if whole < 0 else whole + frac
print convert_to_float('3') # 3.0
print convert_to_float('3/2') # 1.5
print convert_to_float('1 1/2') # 1.5
print convert_to_float('-1 1/2') # -1.5
http://ideone.com/ItifKv

Though you should stear clear of eval completely. Perhaps some more refined version of:
num,den = s.split( '/' )
wh, num = num.split()
result = wh + (float(num)/float(den))
Sorry, meant to be num.split not s.split, and casts. Edited.

I see there are already several good answers here, but I've had good luck with this. It also has the benefit that it will tolerate non-fraction strings if you're parsing mixed sets of data, so there's no need to check if it's a fraction string or not upfront.
def convert_to_float(frac_str):
try:
return float(frac_str)
except ValueError:
try:
num, denom = frac_str.split('/')
except ValueError:
return None
try:
leading, num = num.split(' ')
except ValueError:
return float(num) / float(denom)
if float(leading) < 0:
sign_mult = -1
else:
sign_mult = 1
return float(leading) + sign_mult * (float(num) / float(denom))
>>> convert_to_float('3')
3.0
>>> convert_to_float('1/4')
0.25
>>> convert_to_float('1 2/3')
1.6666666666666665
>>> convert_to_float('-2/3')
-0.6666666666666666
>>> convert_to_float('-3 1/2')
-3.5

That might be a dirty workaround, but you could convert spaces to a + sign to solve the 3rd case (or to a - if your fraction is negative).

def fractionToFloat(fraction):
num = 0
mult = 1
if fraction[:1] == "-":
fraction = fraction[1:]
mult = -1
if " " in fraction:
a = fraction.split(" ")
num = float(a[0])
toSplit = a[1]
else:
toSplit = fraction
frac = toSplit.split("/")
num += float(frac[0]) / float(frac[1])
return num * mult
It can also handle "2 1/1e-8", "-1/3" and "1/5e3".

This implementation avoids using eval and works on pre-2.6 versions of Python.
# matches a string consting of an integer followed by either a divisor
# ("/" and an integer) or some spaces and a simple fraction (two integers
# separated by "/")
FRACTION_REGEX = re.compile(r'^(\d+)(?:(?:\s+(\d+))?/(\d+))?$')
def parse(x):
i, n, d = FRACTION_REGEX.match(x).groups()
if d is None: n, d = 0, 1 # if d is None, then n is also None
if n is None: i, n = 0, i
return float(i) + float(n) / float(d)
To test:
>>> for x in ['1', '1/2', '1 2/3']: print(repr(parse(x)))
...
1.0
0.5
1.6666666666666665

Depending on what syntax you want to support for your fractions, eval('+'.join(s.split())) (with true division in place -- i.e., Python 3 or from __future__ import division in Python 2 -- might work. It would cover all the cases you mention, in particular.

>>> s="1/2"
>>> eval('/'.join(map(str,map(float,s.split("/")))))
0.5
>>> s="3/5"
>>> eval('/'.join(map(str,map(float,s.split("/")))))
0.59999999999999998

Related

converitng ASCII values of a string to base 3 number representation 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]

Function returning 1 instead of the reverse of the Number

Hey I have this function in python3 , can anyone explain why it is giving 1 as output instead of the number as reverse
def reverse(a , rev):
if a > 0:
d = a % 10
rev = (rev * 10) + d
reverse(a/10 , rev)
return rev
b = input("Enter the Number")
x = reverse(b , 0)
print(x)
You need to:
use integer division (//)
capture the value returned from the recursive call, and return it
convert the string input to number (int())
Corrected script:
def reverse(a, rev):
if a > 0:
d = a % 10
rev = (rev * 10) + d
return reverse(a//10, rev)
return rev
b = input("Enter the Number")
x = reverse(int(b), 0)
print(x)
I'm not sure why you're doing it like that. Seems like the following is easier
def rev(a):
return int(str(a)[::-1])
Anyway, I believe you should use "//" instead of "/" for dividing without the rest in python 3?

How to reverse an int in python?

I'm creating a python script which prints out the whole song of '99 bottles of beer', but reversed. The only thing I cannot reverse is the numbers, being integers, not strings.
This is my full script,
def reverse(str):
return str[::-1]
def plural(word, b):
if b != 1:
return word + 's'
else:
return word
def line(b, ending):
print b or reverse('No more'), plural(reverse('bottle'), b), reverse(ending)
for i in range(99, 0, -1):
line(i, "of beer on the wall")
line(i, "of beer"
print reverse("Take one down, pass it around")
line(i-1, "of beer on the wall \n")
I understand my reverse function takes a string as an argument, however I do not know how to take in an integer, or , how to reverse the integer later on in the script.
Without converting the number to a string:
def reverse_number(n):
r = 0
while n > 0:
r *= 10
r += n % 10
n /= 10
return r
print(reverse_number(123))
You are approaching this in quite an odd way. You already have a reversing function, so why not make line just build the line the normal way around?
def line(bottles, ending):
return "{0} {1} {2}".format(bottles,
plural("bottle", bottles),
ending)
Which runs like:
>>> line(49, "of beer on the wall")
'49 bottles of beer on the wall'
Then pass the result to reverse:
>>> reverse(line(49, "of beer on the wall"))
'llaw eht no reeb fo selttob 94'
This makes it much easier to test each part of the code separately and see what's going on when you put it all together.
Something like this?
>>> x = 123
>>> str(x)
'123'
>>> str(x)[::-1]
'321'
best way is
x=12345
a=str(x)[::-1]\\ In this process i have create string of inverse of integer (a="54321")
a=int(a) \\ Here i have converted string a in integer
or
one line code is
a=int(str(x)[::-1]))
def reverse(x):
re = 0
negative = x < 0
MAX_BIG = 2 ** 31 -1
MIN_BIG = -2 ** 31
x = abs(x)
while x != 0:
a = int(x % 10)
re = re * 10 + a
x = int(x // 10)
reverse = -1 * re if negative else re
return 0 if reverse < MIN_BIG or reverse > MAX_BIG else reverse
this is for 32 - bit integer ( -2^31 ; 2^31-1 )
def reverse_number(n):
r = 0
while n > 0:
r = (r*10) + (n % 10)
print(r)
r *=10
n //= 10
return r
print(reverse_number(123))
You can cast an integer to string with str(i) and then use your reverse function.
The following line should do what you are looking for:
def line(b, ending):
print reverse(str(b)) or reverse('No more'), plural(reverse('bottle'),reverse(str(b))), reverse(ending)
Original number is taken in a
a = 123
We convert the int to string ,then reverse it and again convert in int and store reversed number in b
b = int("".join(reversed(str(a))))
Print the values of a and b
print(a,b)
def reverse_number(n):
r = 0
while n > 0:
r *= 10
r += n % 10
n /= 10
return r
print(reverse_number(123))
This code will not work if the number ends with zeros, example 100 and 1000 return 1
def reverse(num):
rev = 0
while(num != 0):
reminder = num % 10
rev = (rev * 10 ) + reminder
num = num // 10
print ("Reverse number is : " , rev )
num=input("enter number : ")
reverse(int(num))
#/ always results into float
#// division that results into whole number adjusted to the left in the number line
I think the following code should be good to reverse your positive integer.
You can use it as a function in your code.
n = input() # input is always taken as a string
rev = int(str(n)[::-1])
If you are having n as integer then you need to specify it as str here as shown. This is the quickest way to reverse a positive integer
import math
def Function(inputt):
a = 1
input2 = inputt
while(input2 > 9):
input2 = input2/10
a = a + 1
print("There are ", a, " numbers ")
N = 10
m = 1
print(" THe reverse numbers are: ")
for i in range(a):
l = (inputt%N)/m
print(math.floor(l), end = '')
N = N*10
m = m*10
print(" \n")
return 0
enter = int(input("Enter the number: "))
print(Function(enter))
More robust solution to handle negative numbers:
def reverse_integer(num):
sign = [1,-1][num < 0]
output = sign * int(str(abs(num))[::-1])
An easy and fast way to do it is as follows:
def reverse(x: int|str) -> int:
reverse_x = int(''.join([dgt for dgt in reversed(num:=str(x)) if dgt != '-']))
if '-' in num:
reverse_x = -reverse_x'
return reverse_x
First we create a list (using list comprehension) of the digits in reverse order. However, we must exclude the sign (otherwise the number would turn out like [3, 2, 1, -]). We now turn the list into a string using the ''.join() method.
Next we check if the original number had a negative sign in it. If it did, we would add a negative sign to reverse_x.
Easily you can write this class:
class reverse_number:
def __init__(self,rvs_num):
self.rvs_num = rvs_num
rvs_ed = int(str(rvs_num)[::-1])
print(rvs_ed)
You can use it by writing:
reverse_number(your number)
I have written it in a different way, but it works
def isPalindrome(x: int) -> bool:
if x<0:
return False
elif x<10:
return True
else:
rev=0
rem = x%10
quot = x//10
rev = rev*10+rem
while (quot>=10):
rem = quot%10
quot = quot//10
rev = rev*10+rem
rev = rev*10+quot
if rev==x:
return True
else:
return False
res=isPalindrome(1221)

convert an alphanumeric string into a numeric one [duplicate]

This question already has answers here:
Python equivalent to atoi / atof
(7 answers)
Closed 9 years ago.
I looked around and I do not see a clear answer for Python to convert an alphanumeric string to a numeric one. Here is an example of numbers I would like to convert.
"1234alpha" --> 1234
"a1234asdf" --> 0
"1234.56yt" --> 1234.56
Any advice would be appreciated.
DK
For a change itertools and no regex:
>>> import itertools as it
>>> number = ''.join(it.takewhile(str.isdigit, '123dfd'))
>>> int(number) if number else 0
123
>>> number = ''.join(it.takewhile(str.isdigit, 'a123dfd'))
int(number) if number else 0
0
Somewhat uglier it works for floats:
>>> number = ''.join(it.takewhile(lambda x: x.isdigit() or
x == '.', '123.45dfd'))
>>> float(number) if number else 0
123.45
Floats, negatives:
def make_number(alphanum):
sign = 1
if alphanum and alphanum[0] in '+-':
sign = int(alphanum[0] + '1')
alphanum = alphanum[1:]
try:
return float(''.join(it.takewhile(lambda x: x.isdigit()
or x == '.', alphanum))) * sign
except ValueError:
return 0
Conclusion: Changing the requirements along the way can turn a simple solution into a complicated one.
To support positive/negative integer/float numbers, you could use a slightly modified regexp from Extract float/double value:
import re
re_float = re.compile("""(?x)
^
[+-]?\ * # first, match an optional sign *and space*
( # then match integers or f.p. mantissas:
\d+ # start out with a ...
(
\.\d* # mantissa of the form a.b or a.
)? # ? takes care of integers of the form a
|\.\d+ # mantissa of the form .b
)
([eE][+-]?\d+)? # finally, optionally match an exponent
""")
def extract_number(s, default=None):
m = re_float.match(s)
if not m:
return default # no number found
f = float(m.group(0)) #XXX to support huge numbers, try/except int() first
return int(f) if f.is_integer() else f
Example
for s in sys.stdin:
print(extract_number(s, default=0))
Input
1234alpha
a1234asdf
1234.56yt
-1e20.
Output
1234
0
1234.56
-100000000000000000000
You can use the re module:
import re
def alp(s):
m = re.match('\d+', s)
return int(m.group(0)) if m is not None and m.start() == 0 else 0
In [3]: alp('a1234asdf')
Out[3]: 0
In [4]: alp('1234alpha')
Out[4]: 1234
If you want to include negative integers:
def alp_neg(s):
m = re.match('[+-]?\d+', s)
return int(m.group(0)) if m is not None and m.start() == 0 else 0
If you want floats too:
def alp_floats(s):
m = re.match('[+-]?\d+(\.\d+)?', s)
return float(m.group(0)) if m is not None and m.start() == 0 else 0
In [7]: alp_floats('-12.2ss31.232sadas')
Out[7]: -12.2
import re
def str_to_int(string):
match = re.match("\d+", string)
if match:
try:
return int(match.group())
except ValueError:
return float(match.group())
else:
return 0
str_to_int("1234alpha")
1234
str_to_int("a1234asdf")
0
import ast
from itertools import takewhile
ast.literal_eval(''.join(takewhile(lambda x: x<='9', string)) or '0')
When the rules for what is OK become hard to define, you might consider this binary search approach that tries to find the bound.
def binsearch_prefix(seq, predicate):
best_upper = 0
lower, upper = 0, len(seq)
while lower < upper:
mid = (lower + upper) / 2
if predicate(seq[:mid]):
best_upper = mid
lower = mid + 1
else:
upper = mid
return seq[:best_upper]
It will return the part of the string that you consider acceptable. For example, this could be your accept function:
def can_float(s):
try:
float(s)
return True
except ValueError:
return False
Example:
print binsearch_prefix(can_float, "1234alpha") # "1234"
print binsearch_prefix(can_float, "a1234asdf") # ""
print binsearch_prefix(can_float, "1234.56yt") # "1234.56"
You may then format the prefix any way you like.
Maybe use regular expressions?
import re
def str2num(s):
try:
num = re.match(r'^([0-9]+)', s).group(1)
except AttributeError:
num = 0
return int(num)
print str2num('1234alpha')
print str2num('a1234asdf')
Output:
1234
0

A python code to convert a number from any base to the base of 10 giving errors . What is wrong with this code?

import math
def baseencode(number, base):
##Converting a number of any base to base10
if number == 0:
return '0'
for i in range(0,len(number)):
if number[i]!= [A-Z]:
num = num + number[i]*pow(i,base)
else :
num = num + (9 + ord(number[i])) *pow(i,base)
return num
a = baseencode('20',5)
print a
Errors I get are
Traceback (most recent call last):
File "doubtrob.py", line 19, in <module>
a = baseencode('20',5)
File "doubtrob.py", line 13, in baseencode
if number[i]!= [A-Z]:
NameError: global name 'A' is not defined
Isn't int(x, base) what you need?
int('20',5) # returns the integer 10
You're confusing Python with... Perl or something...
if not ('A' <= number[i] <= 'Z'):
A more comprehensive solution to this problem may look like this:
import string
# Possible digits from the lowest to the highest
DIGITS = '%s%s' % (string.digits, string.lowercase)
def baseencode(num, base):
result = 0
positive = True
# If a number is negative let's remove the minus sign
if num[0] == '-':
positive = False
num = num[1:]
for i, n in enumerate(num[::-1]):
# Since 0xff == 0xFF
n = n.lower()
result += DIGITS.index(n) * base ** i
if not positive:
result = -1 * result
return result
Basically whilst converting a number to base 10 it's easiest to start from the last digit, multiply it by the base raised to the current position (DIGITS.index(n) * base ** i).
BTW, in my understanding it's a Python exercise, but if it's not there's a builtin function for that - int:
int(x[, base]) -> integer
Other bugs in the code:
1. You didn't initialize variable num that you used to store results.
2. you need to convert number[i] from char to int before you can apply multiplication/addition.
num = num + int(number[i]) * pow(i,base)
There are many errors in your code. To begin with,
number[i] != [A-Z]
is not Python syntax at all. What you probably want is
number[i].isdigit()
Furthermore, the
if number == 0:
return '0'
part should probably be
if number == '0':
return 0
but actually, there is no need to special-case this at all. Another problem is that you interpreting the first character as "ones", i.e. lowest significant. There are a few more problems, but maybe this will get you going...
That said, you could simply use
int('20',5)
import math
def base_encode(number, base):
"""Convert number in given base to equivalent in base10
#param number: string, value to convert (case-insensitive)
#param base: integer, numeric base of strNumber
#retval: integer, x base(10) == number base(base)
"""
# sanitize inputs
number = str(number).lower()
base = int(base)
# legal characters
known_digits = '0123456789abcdefghijklmnopqrstuvwxyz'
value = { ch:val for val,ch in enumerate(known_digits) if val<base }
# handle negative values
if number[0]=='-':
sign = -1
number = number[1:]
else:
sign = 1
# do conversion
total = 0
for d in number:
try:
total = total*base + value[d]
except KeyError:
if d in known_digits:
raise ValueError("invalid digit '{0}' in base {1}".format(d, base))
else:
raise ValueError("value of digit {0} is unknown".format(d))
return sign*total
base_encode('20', 5) -> 10
base_encode('-zzz', 36) -> -46655
You probably want
if number[i] not in "ABCDEFGHIJKLMNOPQRSTUVWXYZ":
or
import string
# ...
if number[i] not in string.ascii_uppercase:

Categories

Resources