Skip to main content
Engineering Notes · March 2015

Daily Challenge: Prime Numbers

Portrait of Komang Artha Yasa — technology leader, two decades building digital platforms across marketplaces, retail, logistics, fintech, and banking.

As mentioned before, the tech team at Kosong Satu Network has been running a daily challenge — small problems to exercise our programming logic.

One of the recent ones was a prime number utility that should:

  • Test if a number is prime, and return why if it isn’t.
  • Get the first n prime numbers.
  • Get the list of primes between x and y.

Here’s what I came up with — Go first, then a near-equivalent JavaScript version with Mocha tests.

Golang

File: prime.go

package main

import (
    "fmt"
    "math"
)

const Min = 2

type Prime struct{}

func (p Prime) Is(n int) error {
    if n < Min {
        return fmt.Errorf("prime must be integer greater than %d", Min)
    }

    divider := int(math.Floor(math.Sqrt(float64(n))))
    for i := Min; i <= divider; i++ {
        if n%i == 0 {
            return fmt.Errorf("%d is divisor of %d", i, n)
        }
    }
    return nil
}

func (p Prime) First(n int) []int {
    var (
        r         []int = []int{}
        count     int   = 0
        iteration int   = Min
    )
    for count < n {
        if err := p.Is(iteration); err == nil {
            r = append(r, iteration)
            count++
        }
        iteration++
    }
    return r
}

func (p Prime) Between(x, y int) []int {
    var r []int = []int{}
    if x < Min {
        x = Min
    }
    for i := x; i <= y; i++ {
        if err := p.Is(i); err == nil {
            r = append(r, i)
        }
    }
    return r
}

File: prime_test.go

package main

import (
    "reflect"
    "strconv"
    "strings"
    "testing"
)

func int_to_string_arrays(a []int) []string {
    r := []string{}
    for _, v := range a {
        r = append(r, strconv.Itoa(v))
    }
    return r
}

func TestIsPrime(t *testing.T) {
    type PrimeData struct {
        number int
        reason string
    }
    primes := []PrimeData{
        {number: 1, reason: "prime must be integer greater than 2"},
        {number: 2},
        {number: 3},
        {number: 9, reason: "3 is divisor of 9"},
        {number: 11},
        {number: 12, reason: "2 is divisor of 12"},
        {number: 13},
    }
    prime := Prime{}
    for _, v := range primes {
        expected := (len(v.reason) == 0)
        err := prime.Is(v.number)
        if err != nil && expected {
            t.Errorf("%d expected true got false", v.number)
        }
        if !expected && err.Error() != v.reason {
            t.Errorf("%d expected %s got %s", v.number, v.reason, err.Error())
        }
    }
}

func TestFirstPrimes(t *testing.T) {
    prime := Prime{}
    first_count := 5
    expected := []int{2, 3, 5, 7, 11}
    primes := prime.First(first_count)
    if !reflect.DeepEqual(expected, primes) {
        t.Errorf("first %d primes expected %s got %s",
            first_count,
            strings.Join(int_to_string_arrays(expected), ","),
            strings.Join(int_to_string_arrays(primes), ","))
    }
}

func TestBetweenPrimes(t *testing.T) {
    prime := Prime{}
    x, y := 1, 15
    expected := []int{2, 3, 5, 7, 11, 13}
    primes := prime.Between(x, y)
    if !reflect.DeepEqual(expected, primes) {
        t.Errorf("between %d - %d primes expected %s got %s",
            x, y,
            strings.Join(int_to_string_arrays(expected), ","),
            strings.Join(int_to_string_arrays(primes), ","))
    }
}
➜ primes git:(master) go test
PASS
ok  _/chazuka/challenges/primes 0.006s

JavaScript

File: prime.js

'use strict';
var min = 2;
var reason = (function () {
  var m = '';
  return {
    set:   function (r) { m = r; },
    get:   function ()  { return m; },
    reset: function ()  { m = ''; },
  };
})();

var is = function (n) {
  if (n < min) {
    reason.set('prime must be integer greater than 2');
    return false;
  }

  var sqrt = Math.floor(Math.sqrt(n));
  for (var i = min; i <= sqrt; i++) {
    if (n % i === 0) {
      reason.set(i + ' is divisor of ' + n);
      return false;
    }
  }
  reason.reset();
  return true;
};

var first = function (n) {
  var x = min, y = 0, r = [];
  while (y < n) {
    if (is(x)) { r.push(x); y++; }
    x++;
  }
  return r;
};

var between = function (x, y) {
  var r = [];
  for (var i = x; i <= y; i++) if (is(i)) r.push(i);
  return r;
};

var why = function () { return reason.get(); };

exports.is      = is;
exports.first   = first;
exports.between = between;
exports.why     = why;

File: test.js

const prime  = require('./prime');
const assert = require('assert');

describe('prime', function () {
  describe('#is', function () {
    it('should detect if a number is prime or not and giving a reason when it is not', function () {
      var primes = [
        { number: 1,  expected: false, reason: 'prime must be integer greater than 2' },
        { number: 2,  expected: true },
        { number: 3,  expected: true },
        { number: 9,  expected: false, reason: '3 is divisor of 9' },
        { number: 11, expected: true },
        { number: 12, expected: false, reason: '2 is divisor of 12' },
        { number: 13, expected: true },
      ];
      for (var i = 0; i < primes.length; i++) {
        var o = primes[i];
        assert.equal(prime.is(o.number), o.expected);
        if (!o.expected) assert.equal(prime.why(), o.reason);
      }
    });
  });

  describe('#first', function () {
    it('should giving the first n of prime numbers', function () {
      var primes = prime.first(5);
      assert.equal(primes.length, 5);
      assert.deepEqual(primes, [2, 3, 5, 7, 11]);
    });
  });

  describe('#between', function () {
    it('should giving the array of prime numbers between x,y', function () {
      var primes = prime.between(1, 15);
      assert.equal(primes.length, 6);
      assert.deepEqual(primes, [2, 3, 5, 7, 11, 13]);
    });
  });
});
➜ primes git:(master) mocha
  prime
    #is
      ✓ should detect if a number is prime or not and giving a reason when it is not
    #first
      ✓ should giving the first n of prime numbers
    #between
      ✓ should giving the array of prime numbers between x,y

  3 passing (12ms)

The interesting bit isn’t the algorithm — it’s how similar the two implementations end up looking once you ignore type declarations and idioms. That’s usually the value of doing the same problem in two languages.