J-bob
J-bob

Reputation: 9126

doing arithmetic on a base N number system using arbitrarily defined characters

First off, this is not a homework assignment. I need to this solution for assigning device names for devices being attached to AWS EC2 instances. I'm working in Java.

I'm looking for a solution where I can define an arbitrary set of characters to serve as numerals to represent numbers of base N, and then be able to increment and decrement these values. For example, say I define a base-3 number system with the numeral set {f,g,h}. So starting in "0" in decimal and incrementing, we would have the sequence: f, g, h, gf, gg, gh, hf, hg, hh.

This needs to work with numbers larger than base-10, so a simple mapping between characters and roman numberals won't do the trick.

As for my specific use case, I'll be doing it with assigning device names attached to a machine, but certain letters are forbidden from being used, so I'll be defining a custom set of permitted characters.

I tried implementing this myself and quickly went down a rabbit hole of logic that was tripping me up. It seems like something someone else has likely implemented already, or at least part of it. Any ideas?

Upvotes: 0

Views: 84

Answers (1)

OldCurmudgeon
OldCurmudgeon

Reputation: 65859

Something like this? I use a BigInteger behind the scenes to avoid all overflows and just generate the number on the fly in toString.

class Counter {
    // My current value.
    private BigInteger n;
    // The character set to use.
    private char[] digits = "0123456789".toCharArray();

    public Counter() {
        this(0);
    }

    public Counter(long start) {
        n = BigInteger.valueOf(start);
    }

    public void inc() {
        n = n.add(BigInteger.ONE);
    }

    public void dec() {
        n = n.subtract(BigInteger.ONE);
    }

    public void setDigits(char[] digits) {
        this.digits = digits;
    }

    public String toString() {
        StringBuilder sb = new StringBuilder();
        BigInteger base = BigInteger.valueOf(digits.length);
        for (BigInteger v = n; v.compareTo(BigInteger.ZERO) > 0; v = v.divide(base)) {
            sb.append(digits[v.mod(base).intValue()]);
        }
        return sb.length() == 0 ? "" + digits[0] : sb.reverse().toString();
    }

}

private void test(String s) {
    Counter counter = new Counter();
    counter.setDigits(s.toCharArray());
    for (int i = 0; i < 100; i++, counter.inc()) {
        System.out.println(counter);
    }
}

private void test() {
    test("0123456789");
    test("fgh");
    test("QwErTyUiOpAsDfGhJkLzXcVbNm");
}

Upvotes: 0

Related Questions