0

I'm porting some c code which is doing a modulo on an uint32_t. An uint32_t fits in a Java int bit-wise, but I cannot figure out how to perform a modulo operation on it without converting to a long. This is the code I have right now:

int i = 0xffffffff;
long asUnsigned = Integer.toUnsignedLong(i);
int mod = (int) (asUnsigned % 42L);

Can I perform this modulo calculation without converting to long?

2 Answers 2

7

Use Integer.remainderUnsigned(int dividend, int divisor) (javadoc):

Returns the unsigned remainder from dividing the first argument by the second where each argument and the result is interpreted as an unsigned value.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks mate, you're a saviour! Couldn't find this method for the life of me :)
It might, but these types of methods also serve as substitution points for JITs. From what I can tell, the JDK17 default C2 does not currently substitute it the way it does other Integer methods, but using this method directly is how you ensure you take advantage if/when it gets added.
1

@that other guy's answer is preferred for Java 8+. I'll leave this here in case it's useful for anyone using older versions of Java.


Converting to a long is almost certainly the best way to do this.

Otherwise, you will need to branch; to get the correct result for a negative int value, you will need to adjust for the fact that the unsigned number that the int represents is offset by 232, and this offset generally won't have a remainder of 0 when you divide by the modulus. If the modulus is a constant (42 in your example) then you can hardcode the offset:

static int unsignedMod42(int x) {
    if(x >= 0) {
        return x % 42;
    } else {
        // 2**32 = 4 (mod 42)
        return ((x % 42) + 42 + 4) % 42;
    }
}

If the modulus is a variable then you have to compute the correct offset at runtime:

static int unsignedMod(int x, int y) {
    if(y <= 0 || y * y <= 0) {
        throw new IllegalArgumentException("y = " + y);
    } else if(x >= 0) {
        return x % y;
    } else {
        // compute 2**32 mod y, by repeated squaring
        int offset = 2;
        for(int i = 0; i < 5; ++i) { offset = (offset * offset) % y; }
        return ((x % y) + y + offset) % y;
    }
}

Note that because the offset here is being computed by repeated squaring, we can't allow a modulus for which the multiplication might overflow. There is presumably a better way to compute the correct offset - by repeated multiplication would allow a modulus up to Integer.MAX_VALUE / 2, for example.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.