Skip to content

Usage & API

Usage & API

The public API lives at the module root (github.com/go-ruby-prime/prime). It is Ruby-shaped but Go-idiomatic: Take / IsPrime / PrimeDivision mirror Prime.take / Prime.prime? / Prime.prime_division, while the surface follows Go conventions — explicit *big.Int values, no global state.

Status: implemented

The library is built and importable as github.com/go-ruby-prime/prime, bound into rbgo as a native module; see Roadmap.

Install

go get github.com/go-ruby-prime/prime

Worked example

package main

import (
	"fmt"
	"math/big"

	"github.com/go-ruby-prime/prime"
)

func main() {
	fmt.Println(prime.Take(5))                       // [2 3 5 7 11]   (Prime.take 5)
	fmt.Println(prime.IsPrime(big.NewInt(561)))      // false          (Carmichael)
	fmt.Println(prime.IsPrime(big.NewInt(7919)))     // true
	fmt.Println(prime.PrimeDivision(big.NewInt(12))) // [[2 2] [3 1]]  (prime_division)
	fmt.Println(prime.PrimeDivision(big.NewInt(-12)))// [[-1 1] [2 2] [3 1]]

	// Reconstruct the integer from its factorisation.
	n := prime.Int(prime.PrimeDivision(big.NewInt(360)))
	fmt.Println(n) // 360

	// Bounded enumeration (Prime.each(11)).
	prime.Each(11, func(p *big.Int) bool { fmt.Print(p, " "); return true })
	fmt.Println() // 2 3 5 7 11
}

Shape

// IsPrime reports whether n is prime (Prime.prime? / Integer#prime?).
func IsPrime(n *big.Int) bool

// Take / First return the first n primes (Prime.take / Prime.first).
func Take(n int) []*big.Int
func First(n int) []*big.Int

// Each yields every prime p <= ubound, stopping early if yield returns false
// (Prime.each(ubound) { |p| ... }).
func Each(ubound int64, yield func(p *big.Int) bool)

// EachPrime returns a stateful generator: each call returns the next prime,
// starting at 2 and continuing forever (the unbounded Prime.each enumerator).
func EachPrime() func() *big.Int

// PrimeDivision returns the [prime, exponent] pairs of n in ascending order
// (Prime.prime_division / Integer#prime_division); a leading [-1, 1] carries a
// negative sign. It panics with ZeroError for n == 0 (MRI's ZeroDivisionError);
// PrimeDivisionErr is the non-panicking form.
func PrimeDivision(n *big.Int) [][2]*big.Int
func PrimeDivisionErr(n *big.Int) ([][2]*big.Int, error)

// Int reconstructs the integer from a prime-division slice
// (Prime.int_from_prime_division), the inverse of PrimeDivision.
func Int(pairs [][2]*big.Int) *big.Int

// Next / Prev return the adjacent prime (Prev returns nil when none exists).
func Next(n *big.Int) *big.Int
func Prev(n *big.Int) *big.Int

type ZeroError struct{} // mirrors Ruby's ZeroDivisionError

Ruby ↔ Go value model

Every integer flows through *big.Int, so a host can map its own Integer to and from this package without precision loss.

RubyGo
Prime.prime?(n) / n.prime?IsPrime(n)
Prime.take(n) / Prime.first(n)Take(n) / First(n)
Prime.each(ubound) { ... }Each(ubound, yield)
Prime.each (enumerator)EachPrime()
Prime.prime_division(n) / n.prime_divisionPrimeDivision(n)
Prime.int_from_prime_division(ps)Int(ps)
ZeroDivisionErrorZeroError (panic)

Algorithm

Primality is exact, not probabilistic, over the range Ruby programs use:

  • Small inputs (< 1000²) are settled by trial division against the primes up to 1000.
  • Larger inputs use Baillie–PSW — a strong base-2 Miller–Rabin test combined with a strong Lucas test (Selfridge parameters). BPSW has no known counterexample and is proven to have none below 2⁶⁴, so the result is exact across the entire 64-bit range and a sound probable-prime test beyond it.
  • Factorisation strips small primes, then splits the cofactor with Pollard’s rho (Brent’s variant), recursing to proven primes.

MRI conformance

Correctness is defined by reference Ruby. A differential oracle runs a corpus through both the system ruby (Prime.prime?, Prime.take, Prime.prime_division, …) and this library and compares the results — not approximated from memory. The oracle tests skip themselves where ruby is not on PATH (e.g. the qemu arch lanes), so the cross-arch builds still validate the library.

Relationship to Ruby

go-ruby-prime/prime is standalone and reusable, and is the prime backend bound into go-embedded-ruby by rbgo as a native module — the same way go-ruby-regexp, go-ruby-yaml and go-ruby-marshal are bound. The dependency runs the other way: this library has no dependency on the Ruby runtime.