#
Algorithm (Base Conversion)
# Let $X=(y_m y_{m-1}\dots y_0.z_{-1}z_{-2}\dots)_{10}$ be a positive real number in the decimal system. We will treat the integer part $Y=(y_m y_{m-1}\dots y_0)$ and fractional part $Z=(z_{-1}z_{-2}\dots)$ individually.
#
# Problem: Find
# \begin{align*}
# \tilde X=(\tilde y_n \tilde y_{n-1}\dots \tilde y_0.\tilde z_{-1} \tilde z_{-2}\dots)_{B} \text{ such that } X_{10}=X_B
# \end{align*}
#
#
#
**Algorithm (Integer Part Y)**
#
# **Initialize**: $\tilde Y_0 = Y$ , $i=0$
# **repeat**
#
# \begin{align*}
# \tilde y_i &= \tilde Y_i \mod B \\
# \tilde Y_{i+1} &=\tilde Y_{i}/B - \tilde y_i/B \\
# i &=i+1
# \end{align*}
#
# **until** $\tilde Y_i=0$
#
#
#
**Algorithm (Fractional Part Z)**
#
# **Initialize**: $\tilde Z_0 = Z$ , $i=0$
# **repeat**
#
# \begin{align*}
# \tilde z_i &= \text{integer}(\tilde Z_i * B) \\
# \tilde Z_{i+1} &=\tilde Z_{i}*B - \tilde y_i \\
# i &=i+1
# \end{align*}
#
# **until** $\tilde Z_i$ is whole or number of relevant digits is reached.
#
#
#
# # Implementation
# ## Function to convert integer part
# In[9]:
def base10_to_newbase_integer(number=5326, base=16):
'''
Converts a integer into a list of digits corresponding to a new base.
Parameters
----------
number : int (5326)
Base 10 input integer
base : int (16)
New base
Yields
------
list
List of digits in the new base.
Notes
-----
I did not add the usual convention to replace the digits above 9 with traditional alphabet notation.
This is work for another day.
'''
tmp = []
factor = 1
if number < 0:
factor = -1
number = -number
while True:
if number < base:
tmp.append(number)
break
else:
number, remainder = divmod(number,base)
tmp.append(int(remainder))
tmp.reverse()
tmp[0] *= factor
return tmp
# A few testruns:
# In[10]:
mytable = []
mytable.append(('a','my converter (B=8)','oct(8)','my converter (B=16)','oct(16)'))
for a in [12345,-12345,7,8,15,16]:
mytable.append((a
,base10_to_newbase_integer(number=a,base=8),oct(a)
,base10_to_newbase_integer(number=a,base=16),hex(a)))
display(HTML(tabulate.tabulate(mytable, tablefmt='html')))
# ## Function to convert fractional part
# In[11]:
def base10_to_newbase_fraction(number=0.6789, base=16,ndigits=5):
'''
Converts the fractional part of a irrational number from base 10 to base B
Parameters
----------
number : float (0.6789)
Base 10 float 0<= number < 1
base : int (16)
New base
ndigits : int (5)
Number of significant digits
Yields
------
list
List of digits in the new base.
Notes
-----
I did not add the usual convention to replace the digits above 9 with traditional alphabet notation.
This is work for another day.
I alos truncate at the maximum number of digits, not round.
'''
tmp = []
digits = 0
while True:
number, integer = math.modf(number*base)
digits += 1
if number == 0 or digits > ndigits:
break
else:
tmp.append(int(integer))
return tmp
# In[12]:
mytable = []
mytable.append(('a','my converter (B=8)','my converter (B=16)'))
for a in [0.6789,-0.6789,0.,0.1,0.2]:
mytable.append((a
,base10_to_newbase_fraction(number=a,base=8)
,base10_to_newbase_fraction(number=a,base=16)))
display(HTML(tabulate.tabulate(mytable, tablefmt='html')))
# ## Now full float conversion:
# In[13]:
def base10_to_newbase(number=12345.6789, base=16,ndigits=5):
'''
Converts the a float base 10 to base B
Parameters
----------
number : float (12345.6789)
Base 10 float
base : int (16)
New base
ndigits : int (5)
Number of significant fractional digits
Yields
------
integer
List of integer digits in the new base.
fractional
List of fractional digits in the new base.
Notes
-----
I did not add the usual convention to replace the digits above 9 with traditional alphabet notation.
This is work for another day.
I alos truncate at the maximum number of digits, not round.
'''
fractional, integer = math.modf(number)
return (base10_to_newbase_integer(number=integer,base=base),
base10_to_newbase_fraction(abs(fractional),base=base,ndigits=ndigits))
# In[14]:
mytable = []
mytable.append(('a','my converter (B=8)','my converter (B=16)'))
for a in [12345,0.6789,12345.6789,-12345.6789,]:
mytable.append((a
,base10_to_newbase(number=a,base=8)
,base10_to_newbase(number=a,base=16)))
display(HTML(tabulate.tabulate(mytable, tablefmt='html')))
# The results of the oct conversion are identical to the textbook solution.