Is there a quick way to compare 3 ternary numbers according to a simple rule set?

mo523 :

Given 3 ternary (base 3) numbers of equal length (they can be padded on the left with zeros), is there a quick and simple way to compare each place value (or column) such that each column is composed of 3 different numbers or 3 of the same number.

For example:

Good pairs:     || Bad pairs:
________________||________________ 
101 | 000 | 012 || 111 | 012 | 002 
212 | 111 | 112 || 122 | 120 | 022
020 | 222 | 212 || 120 | 202 | 102

What I have tried so far

My best solution currently is to add up the 3 numbers, but add them like decimal numbers instead of (so the first good pair would become 333 instead of 1110). Then I check each individual number and check if it is divisible by 3.

At first I was checking if the entire number was divisible by 3, but that fails on a lot of numbers.

00
10
11
--
21 % 3 == 0 

As you can see just dividing by 3 isn't a good enough check since you can tell with a quick glance that the columns actually fail the rules I've set. Here's the method I wrote that checks it the correct way I explained:

//The 3 numbers are originally decimal numbers
private static boolean ternary(int a, int b, int c)
{
    //Convert each number to a ternary number, add them and assign the result to a string
    //This is the best base conversion code I was able to find using native java
    String ternary = Integer.toString(Integer.parseInt(Integer.toString(a, 3))
                + Integer.parseInt(Integer.toString(b, 3)) 
                + Integer.parseInt(Integer.toString(c, 3)));

    //For each digit in the number, check if it is divisible by 3. If not, return false
    for (int i = 0; i < ternary.length(); i++)
        if (Integer.parseInt(ternary.charAt(i) + "") % 3 != 0)
            return false;
    //If all the numbers passed the test, return true
    return true;
}

I have also messed around with adding the numbers as decimal and converting the result to a ternary number and trying to check the properties to no avail. I have a second method that acts like the above but without using Strings. Instead it divides the number by 10000, 1000, etc. since you cannot do .charAt() on a number.

The real Q

My intuition tells me there needs to be a much simpler way to do this, but I have yet to discover it. I have spent way too much trying to come up with an elegant solution, but I'm quite stuck. This may be more of a math question than a programming one, but I think someone here might be able to point me in the right direction. Thanks :)

Jacob G. :

You essentially have a 3x3 matrix where each column must sum to either 0 (all elements in the column are 0), 3 (all elements in the column are 1 or the elements in the column are a permutation of 0, 1, and 2), or 6 (all elements in the column are 2).

Because the columns must sum to either 0, 3, or 6, we can simply check that the sum is divisible by 3.

The code to check this would be as follows:

private static boolean ternary(int a, int b, int c) {
    for (int i = 0; i < 3; i++) {
        if ((a % 3 + b % 3 + c % 3) % 3 != 0) {
            return false;
        }

        a /= 3;
        b /= 3;
        c /= 3;
    }

    return true;
}

Because a, b, and c are input as decimal (base-10), we can use n % 3 (on each value) to get the least significant ternary digits, and return false if their sum is not divisible by 3.

However, we then need to divide each value by 3 to effectively drop the least significant ternary digit.


This is also personal preference, but the calls to a /= 3, b /= 3, and c /= 3 can be moved into the increment portion of the for-loop:

private static boolean ternary(int a, int b, int c) {
    for (int i = 0; i < 3; i++, a /= 3, b /= 3, c /= 3) {
        if ((a % 3 + b % 3 + c % 3) % 3 != 0) {
            return false;
        }
    }

    return true;
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=156893&siteId=1