Chimptest

I recently came accross an instagram post about a chimpanzee who was completing a research task at the Kyoto University. I wondered if I could perform aswell as the chimp. I have recreated the scale and timing of the game for this post below. Hit the reset button, quickly memorize the number pattern and then click the white squares in order from 1-10. Good Luck!


Below is the html and javascript used to program this game.

<script>
    var gameWidth;
    var gameHeight;
    var gameOffset = 20;
    var gameContext;
    var gameCanvas;
    var gameScore;
    var numbers;
    var guessIndex;

    window.onload = function () {
        newGame();
    }

    newGame = function () {
        numbers = Array(40);
        for (var i = 0; i < 40; i++) numbers[i] = i;
        numbers.sort(() => Math.random() - 0.5)
        score.innerHTML = "&nbsp;";
        drawGame();
        startGame();
    }

    startGame = function () {
        guessIndex = 0;
        window.setTimeout(hideGame, 2000);

    }

    hideGame = function () {
        for (var i = 0; i < guessIndex; i++)
            hideNumber(numbers[i], '#112211');
        for (var i = guessIndex; i < 9; i++)
            hideNumber(numbers[i], '#eeeeee');
    }


    window.onresize = function () {
        drawGame();
    }

    clicked = function (e) {
        var rect = gameCanvas.getBoundingClientRect();
        var x = Math.floor(8 * (e.clientX - rect.x - gameOffset) / gameWidth);
        var y = Math.floor(5 * (e.clientY - rect.y - gameOffset) / gameHeight);
        var index = y * 8 + x;

        if (numbers[guessIndex] == index) {
            score.innerHTML = score.innerText + '&nbsp;&#10084;'
            guessIndex++;
        }
        else if (validGuess(index))
            score.innerHTML = score.innerHTML + '&nbsp;&#9760;';
        hideGame();
    }

    validGuess = function (index) {
        var retval = false;
        for (var i = guessIndex; i < 9; i++)
            retval = retval | (numbers[i] == index);
        return retval;
    }

    drawGame = function () {
        var wrapper = document.getElementById("canvasWrapper")
        gameScore = document.getElementById("score");
        gameCanvas = document.getElementById("myCanvas");
        gameCanvas.addEventListener('click', clicked);

        gameWidth = wrapper.clientWidth - 2 * gameOffset;
        gameHeight = Math.floor(5 * gameWidth / 8);
        gameCanvas.width = gameWidth + 2 * gameOffset;
        gameCanvas.height = gameHeight + 2 * gameOffset;

        gameContext = gameCanvas.getContext("2d");
        gameContext.beginPath();
        gameContext.rect(gameOffset, gameOffset, gameWidth, gameHeight);
        gameContext.stroke();

        for (var i = 0; i < 9; i++)
            drawNumber(numbers[i], i + 1);
    }

    drawNumber = function (number, text) {
        drawText(number % 8, Math.floor(number / 8), text);
    }

    hideNumber = function (number, color) {
        saveStyle = gameContext.fillStyle;
        gameContext.fillStyle = color;
        x = number % 8;
        y = Math.floor(number / 8);
        size = Math.floor(gameHeight / 5);
        gameContext.fillRect(gameOffset + x * size + 5, gameOffset + y * size + 5, size - 10, size - 10);
        gameContext.fillStyle = saveStyle;
    }

    drawText = function (x, y, text) {
        var size = Math.floor(gameHeight / 5);
        gameContext.font = 'bold ' + gameWidth / 9 + 'px Arial';
        gameContext.textAlign = "center";
        gameContext.textBaseline = "middle";
        gameContext.fillStyle = "#eeeeee";
        gameContext.fillText(text, gameOffset + 5 + x * size + size / 2, gameOffset + 5 + y * size + size / 2);
    }
</script>
<div id="canvasWrapper">
    <canvas style="background: #112211;" id="myCanvas"></canvas>
    <button type="button" onclick="newGame()">Reset</button><br />
    <span style="font-size: small" id="score"></span>
</div>

Prime Reciprocals, Repetends and Repunits

I was recently watching a numberphile video on YouTube. Matt Parker explores a volume of work by William Shanks. Shanks calclulated the digit length of the repetend for the reciprocals of thousands of prime numbers. His work was carried out by hand in the mid to late 1800s.

Shanks’ table of prime numbers adjacent to the number of repeating digits in its reciprocal

A number is called prime if it is greater than 1 and has only 1 and itself as a divisor. The first 10 prime numbers are 2, 3, 5, 7, 11, 13, 17, 19, 23, 29. The following is c# code finds all primes less than 2^32 or 4,294,967,296 and saves them to a primes.bin.

private void DoIt(){
    BuildPrimeList(uint.MaxValue);
    BinaryWriter primeFile = new BinaryWriter(File.OpenWrite("primes.bin"));
    foreach(uint prime in m_PrimeList)
       primeFile.Write(prime);
    primeFile.Close();
}
 
private void BuildPrimeList(uint maxCandidate)
{
    m_PrimeList = new List<uint>();
    m_PrimeList.Add(2);
    for (uint i = 3; i < maxCandidate; i+=2)
       IsPrime(i);
}

private bool IsPrime(uint candidate)
{
    int maxFactor = (int)Math.Ceiling(Math.Sqrt(candidate))+1;
    foreach (int prime in m_PrimeList){
      if (candidate % prime == 0) return false;
      if (prime > maxFactor) break;
    }
    m_PrimeList.Add(candidate);
    return true;
}

The recipracol of a number n, is simply 1/n and when this fraction is converted to a decimal there are either finite digits or an infinite number of digits that repeat after some time. All prime numbers with the exception of 2 and 5 have decimal representations of their reciprocals containing infinite digits with repeating patterns. Consider the following examples:

prime: 7
reciprocal: 1/7
0.142857142857142857…
repeating digits: 6

prime: 11
reciprocal: 1/11
0.0909090909090909…
repeating digits: 2

prime: 13
reciprocal: 1/13
0.07692307692307692…
repeating digits: 6

When the pages of Shanks’ work appeared on the screen I noticed a relationship between some of the numbers. Many of the primes had a repeating digit count that was only one less then the prime number itself. Similar to 7 above. Then I noticed that some had half the repeating digits of one less than prime.

I paused the video and tested a few on the page and saw that each prime was one more than a multiple of the digit count. I supposed that this might be true for all the numbers in his list. Since I did not have his list available I decided to write the following code create a dictionary that would replicate his work. This way I could perform a test.

private uint RecipricolDigits(uint num, uint max)
{
   uint digitCount = 0;
   List<uint> used = new List<uint>((int)max);
   uint remainder = 1 % num;
   while (!used.Contains(remainder) && digitCount<=max){
     digitCount++;
     used.Add(remainder);
     remainder = (remainder*10) % num;
     }

   return digitCount;
}

For each prime p<1000 I found that the prime was infact one more than a multiple of the number of repeating digits. I was curious if there might be a pattern to the multiples and decided to plot the against the prime number.

for each prime p<1000 I plot c such that c*(number of repeating digits)+1=p

After deciding there was no obvious pattern I took interest in the spike represented by the prime 271. 1/271 in decimal form is 0.00369003690036900…. For a relatively large prime it only has 5 repeating digits and 54*(5)+1=271. At this point I decided to google 271 and found a wikipedia article containing that number.

This article discusses repunit numbers. All digits of a repunit number are 1 therefor 1 , 11, 111, 1111, 11111, …… are repunit numbers. 271 appeared in a list of prime factors of the first thirty base 10 repunit numbers.

https://en.wikipedia.org/wiki/Repunit

Then I started to notice that all of the prime factors in the table had a low number of repeating digits within the decimal representation of its reciprocal. If one were to thumb through Shanks’ pages these repunit factors would definitely stand out as having few repeating digits. At this point I scripted some code that would calculate upto 265371653 rows of Shanks’ data and output a list ordered by the repeating digit count. The following is a partial list of primes in assending order of repeat counts for their reciprocals.

3         1
11        2
37        3
101       4
41        5
271       5
7         6
13        6
237       7
4649      7

73          8
137         8
333667      9
9091        10
21649       11
513239      11
9901        12
53          13
79          13
265371653   13
909091        14
31            15
2906161       15
17            16
5882353       16
2071723       17
19            18
52579         18
3541          20
27961         20

I was amazed and excited to see these numbers reflecting exactly those red numbers in the repunit factorization table from above! As the repunit numbers increase, so does the order that new prime factors appear! 3 being the only exception. I don’t have the computing power to test all primes up to numbers as high as 5363222357 and beyond in a timely matter, but even now as I write this blog I am noticing that the repeating digit count represents the repunit sequence number for which the prime will first appear!

R1 = 1
R2 = 11 = 11 (1/11 has 2 repeating digits)
R3 = 111 = 3 · 37 (1/37 has 3 repeating digits)
R4 = 1111 = 11 · 101 (1/101 has 4 repeating digits)
R5 = 11111 = 41 · 271 (1/41 and 1/271 have 5 repeating digits)
R6 = 111111 = 3 · 7 · 11 · 13 · 37 (1/7 and 1/13 have 6 repeating digits)
R7 = 1111111 = 239 · 4649 (1/239 and 1/4649 have 7 repeating digits)
R8 = 11111111= 11 · 73 · 101 · 137 (1/73 and 1/137 have 8 repeating digits)
R9 = 111111111 = 32 · 37 · 333667 (1/333667 has 9 repeating digits)

PAUSE!!!!! Stop writing this blog!

What? Why stop writing the blog? This is almost interesting for God’s sake! It is years later now and I have resolved to continue adding content to my site so now I will explain.

I was so excited that I might have discovered something original. What would it have felt like to sail the ocean blue and discover a new world? How would it feel when you found out you weren’t the first to discover it? I think this feeling has become common among many of us in the digital world. The experience of starting down what you percieve to be an original road only to realize you are within someone elses old tracks. There is a disappointment associated with learning that an idea is not original. This createive letdown caused me to put it all away and stop writing and stop exploring the repunit/prime recipricol relationship. As a result there would be no more insight, even if it was original, and there would be no more blog.

I discovered that my idea wasn’t original when reading a rather demoralizing sentence the history section of the aforementioned Wikipedia article.

"It was found very early on that for any prime p greater than 5, the period of the decimal expansion of 1/p is equal to the length of the smallest repunit number that is divisible by p."

I was able to glean the above “on my own” very quickly considering the youtube video and ensuing Wikipedia article were at my disposal, as well has having the power of a programming language and modern PC. The road to my “high” was quick and so was the fall.

William Shanks spent a lifetime creating his tables and I admire his dedication to such a tedious task and believe he must have found peace through his accomplishments.

Elegant Hook

I attended Hoover Middle School during the mid 80s and remember my first experience instructing a computer to do something. My school was located in a fairly affluent area of Albuquerque, New Mexico. Albuquerque is the home of Sandia National Laboratories and the public education system there seemed to benefit by having quality technology and science programs. In 7th grade I had a brief chance to learn an introduction to programming on an Apple II with a color monitor. This was an amazing opportunity for the time considering desktop computing was just becoming available to the public! The API was a heavily wrapped version of BASIC that allowed students to write lines of code to control the color of pixels on what was probably a 50×50 grid with a 16 color palette. There were very few commands at the disposal of the students and I imagine the code would have looked something like this:

10 clear white
20 set 4,6 blue
30 set 6,6 blue
40 set 3,4 green
50 set 4,3 green
60 set 5,3 green
70 set 6,3 green
80 set 6,4 green

I remember it was fun to write instructions and create something visual on the screen, but the simplicity of the learning experience did not leave me feeling inspired. As an Eldorado High School freshman, my next programming experience was undertaken to impress Rhonda, a beautiful junior cheerleader. We shared a biology class and I had acquired some useful information about an upcoming multiple choice test. My family owned an MSDOS (pre windows) Leading Edge PC with a proprietary word processor and floppy disk drive. I wanted to print a very small cheat sheet for the test that one could literally digest if compelled to do so, but the options available were too limited. Around this time my mother had just purchased a new printer and asked if I could figure out how to configure it. I remembered a page in the manual showcasing the font sizes available and some associated BASIC code to manipulate the printer from DOS. This would be perfect for my test guide, so I learned a great deal about making my way around DOS, directory structures, file editing and programming in BASIC. My first independently conceived program worked; I shared my tiny test guide with Rhonda and was rewarded with a hug, smile, and a little respect. I had seen some potential for the value of programming and began to tinker more with writing BASIC programs.

Another interest I had at the time was in amateur electronics. I grew up designing and building model train sets which gave me an early introduction into how electricity works. All of these technical hobbies provided a fruitful connection to my father who has EE undergraduate degrees and a PHD in computer science. One weekend, he was teaching me about resistors and how to decode their color bands to identify their value. Each color relates to a whole number from 0-9, with gold and silver indicating the quality or tolerance of the resistor. The first two color bands represent the base value and the third indicates the power of 10 to multiply by.

Resistor color code

For example, the top resistor pictured on the right has a gold band indicating a 5% tolerance, with three color bands Green(5), Black(0) and Red(2).

This relates to 50*10^2 = 5000 Ohms.

5000, 10000, 1000 and Ohm resistors

Selecting a resistor for your project can be a bit trickier because you will not always find a perfect match for the exact value you would need. At times selecting the resistor with the closest value would have to do. After the weekend with my dad, I returned home and wrote a program called “Resistance Assistance” to aid in choosing a resistor. The input of the program was a theoretical resistance value and the output was the closest physical resistor and it’s color code.

I had my program on a 720 KB floppy disc the next time I visited my dad and showed him how it worked. He was proud of the way the program performed and was immediately interested in the code I had written. We spent the following couple of hours examining and refining the code to a more professional standard. It was an experience that impacted my personality as a programmer immensely. I will illustrate the progression of refinement to my code with four examples.

#1 Minimizing Logical Statements

The following lines assign the variable C$ variable to the color that corresponds to the correct color. The code is logically accurate but poorly written. At the time I was unaware of the ELSE statement. Even though the correct color will be assigned in line 40, every following comparison statement after will be run resulting in 7 unnecessary calls.

10  NUMBER=2                                                                    
20  IF NUMBER=0 THEN C$="BLACK"                                                 
30  IF NUMBER=1 THEN C$="BROWN"                                                 
40  IF NUMBER=2 THEN C$="RED"                                                   
50  IF NUMBER=3 THEN C$="ORANGE"                                                
60  IF NUMBER=4 THEN C$="YELLOW"                                                
70  IF NUMBER=5 THEN C$="GREEN"                                                 
80  IF NUMBER=6 THEN C$="BROWN"                                                 
90  IF NUMBER=7 THEN C$="VIOLET"                                                
100 IF NUMBER=8 THEN C$="GRAY"                                                  
110 IF NUMBER=9 THEN C$="WHITE"                                                 
120 PRINT "COLOR " C$

My dad described this problem to me and helped me to imagine this part of the program running hundreds, thousands, or even millions of times. If the number variable was evenly distributed between 0 and 9, the average number of calls wasted would be 5 per run. This would cause noticeable slowdown. We refined the code to include ELSE statements so that once a color was assigned the following IF statements would be ignored. Instead of 10 comparisons being made in the code above, the following only requires 3.

10  NUMBER=2                                                                    
20  IF NUMBER=0 THEN C$="BLACK" ELSE                                                
30  IF NUMBER=1 THEN C$="BROWN" ELSE                                               
40  IF NUMBER=2 THEN C$="RED" ELSE                                                  
50  IF NUMBER=3 THEN C$="ORANGE" ELSE                                               
60  IF NUMBER=4 THEN C$="YELLOW" ELSE                                                
70  IF NUMBER=5 THEN C$="GREEN" ELSE                                                
80  IF NUMBER=6 THEN C$="BROWN" ELSE                                                
90  IF NUMBER=7 THEN C$="VIOLET" ELSE                                               
100 IF NUMBER=8 THEN C$="GRAY" ELSE                                                 
110    NUMBER=9 THEN C$="WHITE"                                                
120 PRINT "COLOR " C$

#2 Using Data Structures

Next, he showed me how the logic structure could be removed entirely and the same task of assigning a color could be accomplished in one line. He introduced me to the method of using an indexed array for the task. First, store the colors in a list (A$) and then simply access the needed color by location (line 50). There would be some overhead to loading the data in lines 10-30, but this would only need be done once in the program. From that point forward, a million color assignments could be made with a minimal million calls as in line 50.

10 DIM A$(10)                                                                   
20 FOR I=1 TO 10: READ A$(I):NEXT                                               
30   DATA "BLACK","BROWN","RED","ORANGE","YELLOW",
          "GREEN","BROWN","VIOLET","GRAY","WHITE"                                                                       
40 NUMBER=2                                                                     
50 C$ = A$(NUMBER)

#3 User Friendliness

The original code I had written worked so long as the resistance values entered were strictly positive integers between one and a billion. What if a user entered a negative value or a non-numeric like the word “dog”? The program would crash. My dad explained that even though we programs new not to do this, we should catch this input error and give the user information and another chance. Also, there should be a way to gracefully exit the program. So, we added a few more lines. Line 120 let the user know how to exit the program and we catch that request on line 140 by exiting back to DOS if entered. Line 150 ensures that the resistance values entered for conversion are in a specified range. If not, the user will be reminded of the limitation and get another shot. These changes made the program more user friendly.

120 PRINT "              PRESS F1+ENTER TO QUIT RESISTENCE ASSISTENCE"          
130 INPUT;"                                                                                   ▐▐▐▐▐▐ ENTER DESIRED RESISTENCE 9  ",N                            
140 IF N=-1 THEN SYSTEM
150 IF N=0 OR N<.1 OR N>=1E+11 THEN PRINT" OOPS! BETWEEN .1 AND 9.54E+10 PLEASE.":GOTO 130

#4 Math can often reduce code

The final step we took with the “Resistance Assistance” program was to make it an actaul tool by employing some mathematics. My assumption upon writing the original code was that a resistor could be found for any value needed. I didn’t stop to think that manufacturers probably couldn’t effectively make billions of different sizes. Prior to my birth, the IEC (International Electrotechnical Commission) created a limited set of resistor values to span the predicted need. (…more). The available resistor values are based on a logarithmic scale, which at the time, I didn’t really understand. So, my dad gave me some quality explanation to help me understand and then integrated the mathematics to speed up and reduce the size of the program once again. This was neat. I had always liked math and really had my eyes opened to how interesting programming could be.

It may have been that day, or during some later conversations, when I heard my dad describe his appreciation for “Elegant Code.” With the interest and patience of a great teacher, he helped refine my rough attempt at solving a problem into something more beautiful. I have come to truly enjoy the process of algorithm refinement. Like a sculptor working to reveal a form that awaits under the stone, I chip away at my rough code until the elegant solution remains. I have been hooked since. Thanks Dad!

Below is the final GWBasic Code

10 KEY OFF                                                                      
20 CLS                                                                          
30 KEY 1, "-1"                                                                  
40 OPTION BASE 1                                                                
50 DIM B(25),R(24),L$(12)                                                       
60 FOR I=1 TO 24:READ B(I):NEXT                                                 
70 DATA 1.05,1.15,1.25,1.4,1.55,1.7,1.9,2.1,2.3,2.55,2.85,3.15,3.45,3.75,4.05,4.45,4.9,5.35,5.9,6.5,7.15,7.85,8.65,9.55                                         
80 FOR I=1 TO 24:READ R(I):NEXT                                                 
90 DATA 1,1.1,1.2,1.3,1.5,1.6,1.8,2,2.2,2.4,2.7,3,3.3,3.6,3.9,4.2,4.7,5.1,5.6,6.2,6.8,7.5,8.2,9.1                                                               
100 FOR I=1 TO 12:READ L$(I):NEXT                                               
110 DATA "SILVER","GOLD","BLACK","BROWN","RED","ORANGE","YELLOW","GREEN","BLUE","VIOLET","GRAY","WHITE"                                                         
120 PRINT "              PRESS F1+ENTER TO QUIT RESISTANCE ASSISTANCE"          
130 INPUT;"                                                                                   ▐▐▐▐▐▐ ENTER DESIRED RESISTANCE 9  ",N                            
140 IF N=-1 THEN SYSTEM
150 IF N=0 OR N<.1 OR N>=1E+11 THEN PRINT" OOPS! BETWEEN .1 AND 9.54E+10 PLEASE.":GOTO 130                                                                      
160 P=INT(LOG(N)/LOG(10))                                                       
170 X=N/(10^P)                                                                  
180 FOR I=1 TO 24                                                               
190 IF X<B(I) THEN A=R(I):GOTO 220                                              
200 NEXT                                                                        
210 X=X/10:P=P+1:GOTO 180                                                       
220 IF P<3 THEN J$="":T=P:GOTO 250                                              
230 IF P>=3 AND P<6 THEN T=P-3:J$="k":GOTO 250                                  
240 IF P>=6 THEN T=P-6:J$="M"                                                   
250 N=A*(10^T)                                                                  
260 BEEP                                                                        
270 H$=L$(INT(A)+3)+" ║ "+L$(10*(A-INT(A))+3)+" ║ "+L$(P+2)                     
280 Z$="▐───────────────────"                                                   
290 Q=LEN(H$)                                                                   
300 K$=LEFT$("▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄",Q+4)                                
310 D$=LEFT$("▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀",Q+4)                                
320 PRINT"                                    ☺ USE A";N J$" Ω RESISTOR         
330 PRINT"                    "K$                                               
340 PRINT" ───────────────────▌ "H$" "Z$"                                       
350 PRINT"                    "D$:GOTO 130

Recursive Radix Calculations

My daughter and I share a special number - 823.  We text it to eachother when the clock says 8:23 or leave a little note with it there.  We also share other instances of the number that we come accross. I sent these photos to her recently:
The address is 823
823 in Binary 1100110111
It's a nice way to let each other know that we are thinking about one another.  Lately, I was wondering what 823 looked like in other bases besides decimal(10) and binary(2). So I wrote a recursive javascript function called convert to do the job.  The user can enter a decimal number and new base to see the equivelant value with the new radix.
<!DOCTYPE HTML>
<html>
<script>
   function doit(){
      var decimal = parseInt(document.getElementById('decimal').value);
      var newBase = parseInt(document.getElementById('newBase').value);
      var output = document.getElementById('output');
      if(newBase > 1 && newBase <10)      
         output.innerHTML = convert(decimal, newBase);
   }
   
   function convert(quotient, base){
      if(quotient > 0){
        var remainder = quotient % base;
        return convert(parseInt(quotient / base), base) + remainder.toString();
      }
      return '';
   }
</script>
<body>
    Decimal: <input type="text" id="decimal">
    New Base:   <input type="text" id="newBase">
    <button type="button" label="doit" onclick="doit();">do it</button>
    <div id="output"></div>
</body>
</html>
And here is the result.  You can enter a decimal number and a base between 2 and 9 inclusively. 
Decimal: New Base: