<p align="center">
  
</p>


## About Hefty Number
Hefty Number is a python library built upon Numpy for doing arithmetic in arbitrary bases with arbitrary precision.

## Libraries


```python
import numpy as np
import math
import sympy as sp

sp.init_printing(order='rev-lex',use_latex='mathjax')
```

## Numbers
Our modern positional number system can be described as a polynomial. 

$$
\large{\begin{align}
a_{n-1}b^{n-1} + a_{n-2}b^{n-2} \ldots a_{1}b^{1} + a_{0}b^{0} \tag{1}
\end{align}}
$$

Where:
* $a$ is a vector of coeficients representing the digits of a number and 
* $b$ is the base of the number in base 10. 
* $n$ is the legth of the number.

We can introduce the notion of a base vector to achieve an easier to work with linear form. If $a_n$ is our vector of coeficients and b is the base of the number then:

$$ 
\large
\dot{a} = [b^{n-1},b^{n-2},\ldots,b^{1},b^{0}] \tag{2}
$$

Given this notation we get the equivalent forms: 

$$
\large{\begin{align}
a_{n-1}b^{n-1} + a_{n-2}b^{n-2} \ldots a_{1}b^{1} + a_{0}b^{0} =  \\
a_{n-1}\dot{a}_{n-1} + a_{n-2}\dot{a}_{n-2} \ldots a_{1}\dot{a}_{1} + a_{0}\dot{a}_{0} = \sum_{i=0}^{n-1}{a_i}{\dot{a}_i} = \\
a\cdot\dot{a}^\intercal
\end{align}}
$$

Where:
* $a$ is a vector of coeficients representing the digits of a number and 
* $b$ is the base of the number. 
* $\dot{a}$ is the base vector

Converting from base is a simple matter of multiplying the coeficients of the number by its base vector transposed. $a\cdot\dot{a}^\intercal$

# Arithmetic


### Multiplication 

Multiplication is built upon the primitive addition operation. Any multiplication algorithm converts its opperands to a series of additions. Consider the multiplication of $425 * 323$. The naive approach is to add one of the opperands as many times as the other one. We could list $425$ to the count of $323$ and then add the list. This is inneficient in terms of the number of operations performed. The more efficient approach, long multiplication, is taught in grade school. 

Let's think about what's going on when perform $425 * 323$ in respect to how these numbers are composed in the positional number system. We define a function that allows us to convert base 10 numbers into a vector representing the decomposition of the numbers: 


```python
def b10ToUnitVect(b10Num):
    rollingSum = 0 
    ls = []
    for i in range(1,len(str(b10Num))+1):
        res = b10Num % 10**i
        m   = res - rollingSum
        ls = [m] + ls
        rollingSum += m
        
    return np.matrix(ls)
```


```python
a = b10ToUnitVect(425)
b = b10ToUnitVect(323)

print(a)
print(b)
```

    [[400  20   5]]
    [[300  20   3]]


Multiplying the two numbers corresponds to multipying each element in one vector with every element of the other. This always produces a square matrix of numbers to be added. We can perform this enumeration by performing row vector by column vector dot product. As follows:


```python
a.T*b
```




    matrix([[1200000,   80000,   12000],
            [  60000,    4000,     600],
            [  15000,    1000,     150],
            [    900,      60,       9]])




```python
(a.T*b).flatten()
```




    matrix([[120000,   8000,   1200,   6000,    400,     60,   1500,    100,
                 15]])




```python
print(425*323 == int((a.T*b).flatten().sum()))
```

    True



```python
a = b10ToUnitVect(4329402105)
a.T*b
```




    matrix([[1200000000000,   80000000000,   12000000000],
            [  90000000000,    6000000000,     900000000],
            [   6000000000,     400000000,      60000000],
            [   2700000000,     180000000,      27000000],
            [    120000000,       8000000,       1200000],
            [            0,             0,             0],
            [       600000,         40000,          6000],
            [        30000,          2000,           300],
            [            0,             0,             0],
            [         1500,           100,            15]], dtype=int64)




```python
a = b10ToUnitVect(4253)
b = b10ToUnitVect(323)

a.T*b
```




    matrix([[1200000,   80000,   12000],
            [  60000,    4000,     600],
            [  15000,    1000,     150],
            [    900,      60,       9]])




```python
np.log10(1000)/np.log10(10)
```




$$3.0$$




```python
5*3+5*20+5*300+20*3+20*20+20*300+400*3+400*20+400*300
```




    137275




```python
k = np.divide(np.log(1000),np.log(10))
# k is numpy.float64 with the value"3.0" 

z = k
k == "3.0"
```




    False




```python
k.
```




$$12.8$$




```python
12*5
```




$$60$$




```python
23/16
```




$$1.4375$$



Where a >= 1 and arg min is an non-negative integer. 

$$\large{\begin{align}
\underset{a \ b \ c}{\operatorname{arg \ min}}\ 23-4^2a-4^1b-4^0c\\
\underset{a}{\operatorname{arg \ min}}\ 23-4^2a = a \\
\underset{b}{\operatorname{arg \ min}}\ 23-4^2a-4^1b = b \\
\underset{c}{\operatorname{arg \ min}}\ 23-4^2b-4^1b-4^0c = c \\
\end{align}}
$$

### Non-vector case


```python
def argmin_s(x,base,power) -> "[min,arg_min]": 
    
    minVal,lastMinVal = 1,1
    fundamental       = base**power
    
    for i in range(0,base):
        minVal = x - fundamental * i
    
        if(minVal < 0):
            return [lastMinVal,i-1]
        if(minVal == 0):
            return [minVal,i]
        
        lastMinVal = minVal
        
    return [minVal,i]


def b10bn(b10Num,base)->"ndarry":
    if(base == 1):
        return np.ones(b10Num)
    
    logNum = math.log(b10Num,base)
    num    = []
    
    if logNum == 1:
        nDigits=2
    else:
        nDigits = math.ceil(logNum)
        
    for i in range(nDigits-1,0,-1):
        b10Num,idx = argmin_s(b10Num,base,i)
        num.append(idx)
        
    num.append(b10Num)
    
    return np.array(num)

def powerVect(base,n):
    num = [1]
    
    if n == 1:
        return np.array(num)
    else:   
        r = 1
        for i in range(n):
            r = base*r
            num = [r] + num
            
        return np.matrix(num)
    
def vectToB10(vect,base):
    rVect = powerVect(base,vect.shape[0]-1)
    return vect*rVect.T
    
a = 9234094032940239493043829839823238928382938329823982389328923898238329832983239823982389232989838938928393893**3
b = b10bn(a,20)
print(b)
print(vectToB10(b,20))
```

    [ 2  3 10  7 16  1  0 18  5  8 11 19 13  0  8  0  3 16  4  5  3  0 19 19 11
      3  9 14 16  9 13  2 14  8  3  1  7 18 13 15 16  7 13  2 13  0 12 16  4  7
     16  5 19 15 17  8 10  3 16 19 10 12 17 18  2  1 13 19 13 16 13  3  4 10  0
      5  1  3  0  3 15 15 16  1 13  8  2  5 11 13 10 10  3 11 19  0 12  3 17 14
      5 11  1 17  9 11 12 13  4 13  0 11 10 17  7  2  8  6 16  3 18 14  5 10  2
     12 10 16  4  7 17 12  4 16 14  3 13  2  5 19 10 11  3  0  3  2 11 16  8 19
      5  5  6 14 12 18  5 18 13  9 19 18 10  8 17 17 11  3 11  7  1  3  2 12 19
     13 17 14 14 12 17  8  6 14 16 19 18  3 16 14  2 19  3 13  2  1  5  4  2 10
     13 14  2 16  9  1 11  4 13  5 19  5  2 12 11  9 19  8 11  5 11  0 17 13 17
      9  9  8  7 19  4 13 15  3  9 18 10  7 14  0  2  5 15 11 16 11  2  6 16 12
      7 17]
    [[ 787377278800261375797310609626570169255923439036910297102455296922779142265402741036829965897731387072437550921294373519676860926877849046796053515656186390238191719866517824579364401567959339626467440107729622759612596819782635071948294923475127692380421387128460609278029340193136528647715203699828982676533576148782791492957]]



```python
math.log(a)
```




    752.7062776521827




```python

```

f3c3eb5e3b265cf38fec9da77f54a3ac7eb26708
ipynb
Jupyter Notebook
Hefty Number Principles.ipynb
Andrewnetwork/HeftyNumber
61aa53611f350a1eab67af755a470af2a9e4c34f
MIT
Hefty Number Principles.ipynb
Andrewnetwork/HeftyNumber
61aa53611f350a1eab67af755a470af2a9e4c34f
MIT
Hefty Number Principles.ipynb
Andrewnetwork/HeftyNumber
61aa53611f350a1eab67af755a470af2a9e4c34f
MIT
Qwen/Qwen-72B
1. YES
2. YES