As mentioned in a previous post, I extended the number conversion algorithm in order to allow for converting numbers with arbitrary digit bases, because I wanted to play around with an idea I’ve had. I questioned myself what properties a number system has where the numbers have digits with prime numbers as there bases? You haven’t heard about such an approach yet? Well, until I had the idea to do it I hadn’t heard about it either. I have become curious and decided to investigate the properties of such numbers. Let’s henceforth call that number system a “primal number system” and numbers expressed in that system “primal numbers”. Each primal number has base 2 for the right most digit, the next higher digit has base 3, then comes base 5, base 7, base 11, etc.
In this article I will show you some of the results I got. In fact, they aren’t ground-breaking, but it was fun to play around with these numbers and some results indeed are interesting, at least for me
Why am I interested in this “theoretical” primal number system? Well, prime numbers are an inherent natural property of integer numbers and somehow it came to my mind that the primal number system might be as inherent as the decimal system, for example. The decimal system somehow had been waiting a long time for being discovered. And I had the feeling this is also the case for primal numbers.
In order to being able to play around with such numbers we need a program which is will convert a decimal number into a primal number. For this purpose, we can use the algorithm shown in my previous article:
def incNumberByValue(digits, baseFn, value):
# The initial overflow is the 'value' to add to the number.
overflow = value
# Traverse list of digits in reverse order.
for i in reversed(xrange(len(digits))):
# If there is no overflow we can stop overflow propagation to next higher digit(s).
if not overflow:
return
sum = digits[i] + overflow
digitBase = baseFn(i, len(digits))
digits[i] = sum % digitBase
overflow = sum / digitBase
def multNumberByValue(digits, baseFn, value):
overflow = 0
# Traverse list of digits in reverse order.
for i in reversed(xrange(len(digits))):
tmp = (digits[i] * value) + overflow
digitBase = baseFn(i, len(digits))
digits[i] = tmp % digitBase
overflow = tmp / digitBase
def convertNumber(srcDigits, srcBaseFn, destDigits, destBaseFn):
for i in xrange(len(srcDigits)):
multNumberByValue(destDigits, destBaseFn, srcBaseFn(i, len(srcDigits)))
incNumberByValue(destDigits, destBaseFn, srcDigits[i])
def createDigitBaseFromListFn(digitBases):
numDigitBases = len(digitBases)
def getDigitBaseFromList(digitIndex, digitsLen):
baseIndex = digitsLen - digitIndex - 1
return digitBases[baseIndex] if baseIndex < numDigitBases else 10000000000
return getDigitBaseFromList
def createConstantDigitBaseFn(base):
def getConstantDigitBase(digitIndex, digitsLen):
return base
return getConstantDigitBase
Furthermore, we need some prime numbers, because we don’t want to calculate them on-the-fly. Let’s write a factory function which returns a pointer to a function which can be used as digit base function like it is required by the code above:
primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, \
61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, \
137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, \
199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, \
277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, \
359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, \
439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, \
521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, \
607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, \
683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, \
773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, \
863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, \
967, 971, 977, 983, 991, 997]
def createPrimeDigitBaseFn():
return createDigitBaseFromListFn(primes)
We can now convert decimal numbers to primal numbers. Let’s do it in a loop:
>>> constFn = createConstantDigitBaseFn(10000000000)
>>> primeFn = createPrimeDigitBaseFn()
>>> for i in range(31):
... srcDigits = [i]
... destDigits = [0, 0, 0, 0]
... convertNumber(srcDigits, constFn, destDigits, primeFn)
... print("{0:>3}: {1}".format(i, destDigits))
...
0: [0, 0, 0, 0]
1: [0, 0, 0, 1]
2: [0, 0, 1, 0]
3: [0, 0, 1, 1]
4: [0, 0, 2, 0]
5: [0, 0, 2, 1]
6: [0, 1, 0, 0]
7: [0, 1, 0, 1]
8: [0, 1, 1, 0]
9: [0, 1, 1, 1]
10: [0, 1, 2, 0]
11: [0, 1, 2, 1]
12: [0, 2, 0, 0]
13: [0, 2, 0, 1]
14: [0, 2, 1, 0]
15: [0, 2, 1, 1]
16: [0, 2, 2, 0]
17: [0, 2, 2, 1]
18: [0, 3, 0, 0]
19: [0, 3, 0, 1]
20: [0, 3, 1, 0]
21: [0, 3, 1, 1]
22: [0, 3, 2, 0]
23: [0, 3, 2, 1]
24: [0, 4, 0, 0]
25: [0, 4, 0, 1]
26: [0, 4, 1, 0]
27: [0, 4, 1, 1]
28: [0, 4, 2, 0]
29: [0, 4, 2, 1]
30: [1, 0, 0, 0]
Nothing surprising so far. The digits cycle through their possible value ranges as expected. But what drew my attention was the series of decimal numbers that correspond to the series of primal numbers “1″, “10″, “100″, and “1000″, because like it is the case with “normal” number bases these values mark the point where a new digit is required and their corresponding decimal values tell you how much values can be represented with fewer digits. Consider the decimal value “100″, for instance. It tells you that you can express 100 values with fewer digits (0..99). So I extended the loop with a few lines that test for such numbers and put them into a list:
>>> l = []
>>> for i in range(50000):
... srcDigits = [i]
... destDigits = [0, 0, 0, 0, 0, 0, 0]
... convertNumber(srcDigits, constFn, destDigits, primeFn)
... sum = 0
... for digit in destDigits:
... sum += digit
... if 1 == sum:
... l.append(i)
...
>>> print(l)
[1, 2, 6, 30, 210, 2310, 30030]
I was curious about what Google would tell me about this number series and soon found questions asking how the number series 1, 2, 6, 30, 210, 2310 might be continued. I found answers, too, and finally ended at Wikipedia telling me that these numbers are so called “primorials“. In short, a primorial number is the product of all prime numbers smaller than a value “n”. So “primorial(13) = 13*11*7*5*3*2*1 = 30030″ which is equal to the primal number “1000000″. While it sounds interesting, this should be no surprise, because the value of each digit place in the primal number system corresponds to a product of prime numbers.
Ok, so what now? Besides having learned about “primorial” function there were no further interesting properties that were obvious to me. So I decided to check how the series of prime numbers itself looks like when they are expressed in the primal number system. I other words, how do prime numbers look like when we convert them into primal number representation?
>>> for prime in primes:
... srcDigits = [prime]
... destDigits = [0, 0, 0, 0, 0]
... convertNumber(srcDigits, constFn, destDigits, primeFn)
... print("{0:>3}: {1}".format(prime, destDigits))
...
2: [0, 0, 0, 1, 0]
3: [0, 0, 0, 1, 1]
5: [0, 0, 0, 2, 1]
7: [0, 0, 1, 0, 1]
11: [0, 0, 1, 2, 1]
13: [0, 0, 2, 0, 1]
17: [0, 0, 2, 2, 1]
19: [0, 0, 3, 0, 1]
23: [0, 0, 3, 2, 1]
29: [0, 0, 4, 2, 1]
31: [0, 1, 0, 0, 1]
37: [0, 1, 1, 0, 1]
41: [0, 1, 1, 2, 1]
43: [0, 1, 2, 0, 1]
47: [0, 1, 2, 2, 1]
53: [0, 1, 3, 2, 1]
59: [0, 1, 4, 2, 1]
61: [0, 2, 0, 0, 1]
67: [0, 2, 1, 0, 1]
71: [0, 2, 1, 2, 1]
73: [0, 2, 2, 0, 1]
79: [0, 2, 3, 0, 1]
83: [0, 2, 3, 2, 1]
89: [0, 2, 4, 2, 1]
97: [0, 3, 1, 0, 1]
101: [0, 3, 1, 2, 1]
103: [0, 3, 2, 0, 1]
107: [0, 3, 2, 2, 1]
109: [0, 3, 3, 0, 1]
113: [0, 3, 3, 2, 1]
127: [0, 4, 1, 0, 1]
131: [0, 4, 1, 2, 1]
137: [0, 4, 2, 2, 1]
139: [0, 4, 3, 0, 1]
149: [0, 4, 4, 2, 1]
151: [0, 5, 0, 0, 1]
157: [0, 5, 1, 0, 1]
163: [0, 5, 2, 0, 1]
167: [0, 5, 2, 2, 1]
173: [0, 5, 3, 2, 1]
179: [0, 5, 4, 2, 1]
181: [0, 6, 0, 0, 1]
191: [0, 6, 1, 2, 1]
193: [0, 6, 2, 0, 1]
197: [0, 6, 2, 2, 1]
199: [0, 6, 3, 0, 1]
211: [1, 0, 0, 0, 1]
. . .
Nice, but I couldn’t find any regularly recurring patterns. Not that I expected any, but without trying…
Then I thought I could investigate all the distances between each pair of subsequent numbers. Of course, the distances are the same as if I measure the distances between prime numbers using decimal system representation. But I asked myself what would happen if I just interpreted the primal numbers as numbers with equal digit bases and then calculated the distances? Let’s consider the prime numbers 7 and 11, for instance. Their difference is 11-7=4. And now lets subtract the corresponding primal numbers 101 and 121 just as if they were decimal numbers, which results in 121-101=20.
So I wrote a program which calculates both, the distances between prime numbers in decimal system and the distances between prime numbers in primal system using the just mentioned interpretation as numbers with equal digit bases. However, this time I used prime numbers up to 100000 in order to get a “big picture”. The following program reads the prime numbers from a file line by line and puts them into a list before it does its calculations:
def readPrimes():
text_file = open("primes.txt", "r")
lines = text_file.readlines()
text_file.close()
return [int(prime) for prime in lines]
primes = getPrimes()
# Calculate and print differences between prime numbers.
primeDiffs = [y - x for x, y in zip(primes, primes[1:])]
primeDiffsSet = sorted(set(primeDiffs))
print primeDiffs
print primeDiffsSet
# Calculate integer values from primal numbers.
constBaseBigFn = createConstantDigitBaseFn(100000000000000000000)
constBaseSmallFn = createConstantDigitBaseFn(15)
primeFn = createPrimeDigitBaseFn()
ints = []
for prime in primes:
# Convert decimal prime number to primal representation.
primalDigits = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
convertNumber([prime], constBaseBigFn, primalDigits, primeFn)
# Interpret primal digits as digits of a number with constant digit bases
# and convert it to a decimal integer.
intDigits = [0]
convertNumber(primalDigits, constBaseSmallFn, intDigits, constBaseBigFn)
# Put the integer value into a list.
ints.append(int(intDigits[0]))
# Calculate and print differences between prime numbers.
intDiffs = [y - x for x, y in zip(ints, ints[1:])]
intDiffsSet = sorted(set(intDiffs))
print intDiffs
print intDiffsSet
And what are the results? Well, I will analyze the results in a subsequent posting
Filed under: fun | Tagged: algorithm, converter, decimal, primal, prime numbers, primorial, programming, python | Leave a Comment »