Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 36 additions & 2 deletions jme3-core/src/main/java/com/jme3/math/FastMath.java
Original file line number Diff line number Diff line change
Expand Up @@ -1203,10 +1203,44 @@ public static float unInterpolateLinear(float value, float min, float max) {
}

/**
* Round n to a multiple of p
* Align n to a multiple of p, where p must be a power of two.
* This is an optimized version that uses bitwise operations.
*
* @param n the value to align
* @param p the alignment value (must be a power of two)
* @return the smallest value greater than or equal to n that is a multiple of p
* @throws IllegalArgumentException if p is not a power of two
*/
public static int alignToPowerOfTwo(int n, int p) {
if (!isPowerOfTwo(p)) {
throw new IllegalArgumentException("p must be a power of two, got: " + p);
}
return ((n - 1) | (p - 1)) + 1;
}

/**
* Round n up to the nearest multiple of p.
* This works for any positive integer p.
*
* @param n the value to round
* @param p the multiple (must be positive)
* @return the smallest value greater than or equal to n that is a multiple of p
* @throws IllegalArgumentException if p is not positive
*/
public static int toMultipleOf(int n, int p) {
return ((n - 1) | (p - 1)) + 1;
if (p <= 0) {
throw new IllegalArgumentException("p must be positive, got: " + p);
}
// For powers of two, use the optimized version
if (isPowerOfTwo(p)) {
return ((n - 1) | (p - 1)) + 1;
}
// Generic implementation for any positive integer
int remainder = n % p;
if (remainder == 0) {
return n;
}
return n + (p - remainder);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,11 @@ public int getBasicAlignment(Object o) {
* @param pos
* the position to align
* @param basicAlignment
* the basic alignment
* the basic alignment (must be a power of two)
* @return the aligned position
*/
public int align(int pos, int basicAlignment) {
return pos==0?pos:FastMath.toMultipleOf(pos, basicAlignment);
return pos==0?pos:FastMath.alignToPowerOfTwo(pos, basicAlignment);
}

/**
Expand Down
74 changes: 74 additions & 0 deletions jme3-core/src/test/java/com/jme3/math/FastMathTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -855,4 +855,78 @@ public void testSphericalToCartesianZ() {
assertEquals(0.0f, retval.getY(), 0.0f);
assertEquals(0.0f, retval.getZ(), 0.0f);
}

@Test
public void testAlignToPowerOfTwo() {
// Test with various power-of-two values
assertEquals(8, FastMath.alignToPowerOfTwo(5, 4));
assertEquals(8, FastMath.alignToPowerOfTwo(8, 4));
assertEquals(16, FastMath.alignToPowerOfTwo(15, 16));
assertEquals(16, FastMath.alignToPowerOfTwo(16, 16));
assertEquals(32, FastMath.alignToPowerOfTwo(17, 16));
assertEquals(1, FastMath.alignToPowerOfTwo(1, 1));
assertEquals(2, FastMath.alignToPowerOfTwo(2, 2));
assertEquals(4, FastMath.alignToPowerOfTwo(3, 4));
assertEquals(64, FastMath.alignToPowerOfTwo(50, 64));
assertEquals(128, FastMath.alignToPowerOfTwo(100, 128));

// Test edge cases
assertEquals(256, FastMath.alignToPowerOfTwo(256, 256));
assertEquals(512, FastMath.alignToPowerOfTwo(257, 256));

// Test that it throws for non-power-of-two values
try {
FastMath.alignToPowerOfTwo(10, 3);
fail("Expected IllegalArgumentException for non-power-of-two");
} catch (IllegalArgumentException e) {
// Expected
}

try {
FastMath.alignToPowerOfTwo(10, 6);
fail("Expected IllegalArgumentException for non-power-of-two");
} catch (IllegalArgumentException e) {
// Expected
}
}

@Test
public void testToMultipleOf() {
// Test with various values including non-powers-of-two
assertEquals(6, FastMath.toMultipleOf(5, 3));
assertEquals(6, FastMath.toMultipleOf(6, 3));
assertEquals(9, FastMath.toMultipleOf(7, 3));
assertEquals(10, FastMath.toMultipleOf(10, 5));
assertEquals(15, FastMath.toMultipleOf(11, 5));
assertEquals(7, FastMath.toMultipleOf(5, 7));
assertEquals(7, FastMath.toMultipleOf(7, 7));
assertEquals(14, FastMath.toMultipleOf(8, 7));

// Test with power-of-two values (should work too)
assertEquals(8, FastMath.toMultipleOf(5, 4));
assertEquals(8, FastMath.toMultipleOf(8, 4));
assertEquals(16, FastMath.toMultipleOf(15, 16));
assertEquals(16, FastMath.toMultipleOf(16, 16));
assertEquals(32, FastMath.toMultipleOf(17, 16));

// Test edge cases
assertEquals(1, FastMath.toMultipleOf(1, 1));
assertEquals(100, FastMath.toMultipleOf(100, 100));
assertEquals(200, FastMath.toMultipleOf(101, 100));

// Test that it throws for non-positive values
try {
FastMath.toMultipleOf(10, 0);
fail("Expected IllegalArgumentException for p=0");
} catch (IllegalArgumentException e) {
// Expected
}

try {
FastMath.toMultipleOf(10, -5);
fail("Expected IllegalArgumentException for negative p");
} catch (IllegalArgumentException e) {
// Expected
}
}
}