Original was not really buggy, but was missing base check for other function, so here one slightly improved, with also balanced range for testing, instead of mostly negative:
# -*- coding: cp1252 -*-
from random import randint
symbols = '0123456789abcdefghijklmnopqrstuvwxyzåäö'
symbol_values = dict(reversed(v) for v in enumerate(symbols))
def int_to_base(number, base):
if base > len(symbols) or base < 2:
raise ValueError('Invalid base %i' % base)
s = ''
if number < 0:
number, neg = -number, True
else:
neg = False
while number:
number, this = divmod(number, base)
s = symbols[this] + s
return str((neg * '-' ) + s)
def value_in_base(string, base):
if base > len(symbols) or base < 2:
raise ValueError('Invalid base %i' % base)
minus = string.lstrip().startswith('-')
v = sum(symbol_values[sym] * base ** power
for power, sym in enumerate(reversed(string.lower().strip(' -'))))
return -v if minus else v
num_check = 100
for count in range(num_check):
num, b = randint(-10000, 10000), randint(2,len(symbols))
print('\nOriginal %i' % num)
v = int_to_base(num, b)
print('%s base %i' % (v, b))
print(value_in_base(v, b))
assert value_in_base(v, b) == num
What is missing is unary coding . Also if all symbols would be defined for UTF-16, big numbers could be printed in UTF-16 in base 65536, otherwise with printable set of 256 letters, numbers binary representation could be easily printed as base 256, one letter per byte.
pyTony
pyMod
5,359 posts since Apr 2010
Reputation Points: 782
Solved Threads: 852
Of course the bug had to be there, if number is 0, the loop is not entered so line 20 must be revised to:
return str((neg * '-') + s) if s else '0'
pyTony
pyMod
5,359 posts since Apr 2010
Reputation Points: 782
Solved Threads: 852
To be more restrictive on value of the symbols in numbers you can initialize each time the dictionary for acceptable symbols:
def value_in_base(string, base):
if base > len(symbols) or base < 2:
raise ValueError('Invalid base %i' % base)
symbol_values = dict(reversed(v) for v in enumerate(symbols[:base]))
minus = string.lstrip().startswith('-')
v = sum(symbol_values[sym] * base ** power
for power, sym in enumerate(reversed(string.lower().lstrip(' -'))))
return -v if minus else v
Or you can be satisfied with simple linear search:
def value_in_base(string, base):
if base > len(symbols) or base < 2:
raise ValueError('Invalid base %i' % base)
minus = string.lstrip().startswith('-')
string = string.lower().lstrip('-')
assert all(c in symbols[:base] for c in string)
v = sum(symbols.find(sym) * base ** power
for power, sym in enumerate(reversed(string)))
return -v if minus else v
pyTony
pyMod
5,359 posts since Apr 2010
Reputation Points: 782
Solved Threads: 852
I have stated in post in related thread in C forum, that also planned corner cases are necessary, but in my opinion it is good to through in some random values to sometimes catch left out corner values. Of course that is connected with planning for the program, so for new program I think it is good to do the logic of program and test cases side by side. First test to pass would be example usage scenarios for the code. Finding bug places is usually closely rfelated to branching conditions, user input values, exceptions from IO...
Like Dijkstra said it is generally not possible to prove that bug does not exist, only that you have .
pyTony
pyMod
5,359 posts since Apr 2010
Reputation Points: 782
Solved Threads: 852