Task: Nimber arithmetic




Go: package main

import (
    "fmt"
    "strings"
)


func hpo2(n uint) uint { return n & (-n) }


func lhpo2(n uint) uint {
    q := uint(0)
    m := hpo2(n)
    for m%2 == 0 {
        m = m >> 1
        q++
    }
    return q
}


func nimsum(x, y uint) uint { return x ^ y }


func nimprod(x, y uint) uint {
    if x < 2 || y < 2 {
        return x * y
    }
    h := hpo2(x)
    if x > h {
        return nimprod(h, y) ^ nimprod(x^h, y) 
    }
    if hpo2(y) < y {
        return nimprod(y, x) 
    }
    xp, yp := lhpo2(x), lhpo2(y)
    comp := xp & yp
    if comp == 0 {
        return x * y 
    }
    h = hpo2(comp)
    
    return nimprod(nimprod(x>>h, y>>h), 3<<(h-1))
}

type fnop struct {
    fn func(x, y uint) uint
    op string
}

func main() {
    for _, f := range []fnop{{nimsum, "+"}, {nimprod, "*"}} {
        fmt.Printf(" %s |", f.op)
        for i := 0; i <= 15; i++ {
            fmt.Printf("%3d", i)
        }
        fmt.Println("\n--- " + strings.Repeat("-", 48))
        for i := uint(0); i <= 15; i++ {
            fmt.Printf("%2d |", i)
            for j := uint(0); j <= 15; j++ {
                fmt.Printf("%3d", f.fn(i, j))
            }
            fmt.Println()
        }
        fmt.Println()
    }

    a := uint(21508)
    b := uint(42689)
    fmt.Printf("%d + %d = %d\n", a, b, nimsum(a, b))
    fmt.Printf("%d * %d = %d\n", a, b, nimprod(a, b))
}


Java: import java.util.function.IntBinaryOperator;

public class Nimber {
    public static void main(String[] args) {
        printTable(15, '+', (x, y) -> nimSum(x, y));
        System.out.println();
        printTable(15, '*', (x, y) -> nimProduct(x, y));
        System.out.println();

        int a = 21508, b = 42689;
        System.out.println(a + " + " + b +  " = " + nimSum(a, b));
        System.out.println(a + " * " + b +  " = " + nimProduct(a, b));
    }

    
    public static int nimSum(int x, int y) {
        return x ^ y;
    }

    
    public static int nimProduct(int x, int y) {
        if (x < 2 || y < 2)
            return x * y;
        int h = hpo2(x);
        if (x > h)
            return nimProduct(h, y) ^ nimProduct(x ^ h, y);
        if (hpo2(y) < y)
            return nimProduct(y, x);
        int xp = lhpo2(x), yp = lhpo2(y);
        int comp = xp & yp;
        if (comp == 0)
            return x * y;
        h = hpo2(comp);
        return nimProduct(nimProduct(x >> h, y >> h), 3 << (h - 1));
    }

    
    private static int hpo2(int n) {
        return n & -n;
    }
    
    
    private static int lhpo2(int n) {
        int q = 0, m = hpo2(n);
        for (; m % 2 == 0; m >>= 1, ++q) {}
        return q;
    }

    private static void printTable(int n, char op, IntBinaryOperator func) {
        System.out.print(" " + op + " |");
        for (int a = 0; a <= n; ++a)
            System.out.printf("%3d", a);
        System.out.print("\n--- -");
        for (int a = 0; a <= n; ++a)
            System.out.print("---");
        System.out.println();
        for (int b = 0; b <= n; ++b) {
            System.out.printf("%2d |", b);
            for (int a = 0; a <= n; ++a)
                System.out.printf("%3d", func.applyAsInt(a, b));
            System.out.println();
        }
    }
}