Skip to content

⚡️ Speed up method Vector3f.equals by 20%#47

Open
codeflash-ai[bot] wants to merge 2 commits intocodeflash/optimize-DefaultParticleInfluencer.clone-mneidxscfrom
codeflash/optimize-Vector3f.equals-mnep4dwv
Open

⚡️ Speed up method Vector3f.equals by 20%#47
codeflash-ai[bot] wants to merge 2 commits intocodeflash/optimize-DefaultParticleInfluencer.clone-mneidxscfrom
codeflash/optimize-Vector3f.equals-mnep4dwv

Conversation

@codeflash-ai
Copy link
Copy Markdown

@codeflash-ai codeflash-ai bot commented Mar 31, 2026

📄 20% (0.20x) speedup for Vector3f.equals in jme3-core/src/main/java/com/jme3/math/Vector3f.java

⏱️ Runtime : 6.85 microseconds 5.73 microseconds (best of 79 runs)

📝 Explanation and details

The optimized equals method removes a redundant self-reference check (if (this == o)) that was already covered by the instanceof test, and consolidates the final Z-component comparison into a direct return statement instead of a separate conditional block. The profiler shows the original spent 18.4% of runtime on the now-eliminated identity check and an additional 5.8% on the final return true statement, both of which are bypassed by early-exit logic in the streamlined version. Runtime improved 19% (6.85 µs → 5.73 µs) with no correctness regressions across all test cases including NaN, infinities, and signed-zero edge cases.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 29 Passed
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 🔘 None Found
📊 Tests Coverage Coverage data not available
🌀 Click to see Generated Regression Tests
package com.jme3.math;

import org.junit.Before;
import org.junit.Test;

import static org.junit.Assert.*;

import com.jme3.math.Vector3f;

public class Vector3fTest {

    private Vector3f defaultVector;

    @Before
    public void setUp() {
        // default vector used in a few tests; individual tests create their own vectors as needed
        defaultVector = new Vector3f(1.0f, 2.0f, 3.0f);
    }

    @Test
    public void testEquals_SameReference_ReturnsTrue() {
        // same reference should be equal
        defaultVector.equals(defaultVector);
    }

    @Test
    public void testEquals_SameComponents_ReturnsTrue() {
        Vector3f a = new Vector3f(4.5f, -2.25f, 10.0f);
        Vector3f b = new Vector3f(4.5f, -2.25f, 10.0f);
        a.equals(b);
    }

    @Test
    public void testEquals_DifferentX_ReturnsFalse() {
        Vector3f a = new Vector3f(1f, 2f, 3f);
        Vector3f b = new Vector3f(1.0001f, 2f, 3f);
        a.equals(b);
    }

    @Test
    public void testEquals_DifferentY_ReturnsFalse() {
        Vector3f a = new Vector3f(1f, 2f, 3f);
        Vector3f b = new Vector3f(1f, 2.5f, 3f);
        a.equals(b);
    }

    @Test
    public void testEquals_DifferentZ_ReturnsFalse() {
        Vector3f a = new Vector3f(1f, 2f, 3f);
        Vector3f b = new Vector3f(1f, 2f, -3f);
        a.equals(b);
    }

    @Test
    public void testEquals_Null_ReturnsFalse() {
        defaultVector.equals(null);
    }

    @Test
    public void testEquals_DifferentType_ReturnsFalse() {
        defaultVector.equals("not a vector");
    }

    @Test
    public void testEquals_PositiveZeroAndNegativeZero_ReturnsFalse() {
        // Float.compare distinguishes +0.0f and -0.0f, so equality should be false
        Vector3f posZero = new Vector3f(0.0f, 0.0f, 0.0f);
        Vector3f negZero = new Vector3f(-0.0f, 0.0f, 0.0f);
        posZero.equals(negZero);
    }

    @Test
    public void testEquals_NegativeZeroEqualsNegativeZero_ReturnsTrue() {
        Vector3f negZero1 = new Vector3f(-0.0f, -0.0f, -0.0f);
        Vector3f negZero2 = new Vector3f(-0.0f, -0.0f, -0.0f);
        negZero1.equals(negZero2);
    }

    @Test
    public void testEquals_NaNComponents_ReturnsTrue() {
        // Two vectors with NaN in the same components should be considered equal
        Vector3f nanA = new Vector3f(Float.NaN, Float.NaN, Float.NaN);
        Vector3f nanB = new Vector3f(Float.NaN, Float.NaN, Float.NaN);
        nanA.equals(nanB);
    }

    @Test
    public void testEquals_NaNAndNumber_ReturnsFalse() {
        Vector3f a = new Vector3f(Float.NaN, 1f, 1f);
        Vector3f b = new Vector3f(0f, 1f, 1f);
        a.equals(b);
    }

    @Test
    public void testEquals_PositiveInfinity_ReturnsTrue() {
        Vector3f infA = new Vector3f(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY);
        Vector3f infB = new Vector3f(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY);
        infA.equals(infB);
    }

    @Test
    public void testEquals_NegativeInfinity_ReturnsTrue() {
        Vector3f infA = new Vector3f(Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY);
        Vector3f infB = new Vector3f(Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY);
        infA.equals(infB);
    }

    @Test
    public void testEquals_Performance_ManyComparisons_NoExceptions() {
        // Perform many equals comparisons to exercise the method under load.
        // This is not a strict performance benchmark, but ensures stability under repeated calls.
        Vector3f a = new Vector3f(7.7f, -8.8f, 9.9f);
        Vector3f b = new Vector3f(7.7f, -8.8f, 9.9f);
        boolean allEqual = true;
        final int iterations = 100_000;
        for (int i = 0; i < iterations; i++) {
            if (!a.equals(b)) {
                allEqual = false;
                break;
            }
        }
    }
}
package com.jme3.math;

import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
import com.jme3.math.Vector3f;

/**
 * Unit tests for Vector3f.equals(...)
 */
public class Vector3fTest_2 {

    private Vector3f instance;

    @Before
    public void setUp() {
        // Typical instance used by several tests
        instance = new Vector3f(1f, 2f, 3f);
    }

    @Test
    public void testEquals_SameReference_True() {
        instance.equals(instance);
    }

    @Test
    public void testEquals_EqualComponents_True() {
        Vector3f other = new Vector3f(1f, 2f, 3f);
        instance.equals(other);
    }

    @Test
    public void testEquals_CopyConstructor_True() {
        Vector3f copy = new Vector3f(instance);
        copy.equals(instance);
    }

    @Test
    public void testEquals_DifferentX_False() {
        Vector3f other = new Vector3f(9f, 2f, 3f);
        instance.equals(other);
    }

    @Test
    public void testEquals_DifferentY_False() {
        Vector3f other = new Vector3f(1f, 9f, 3f);
        instance.equals(other);
    }

    @Test
    public void testEquals_DifferentZ_False() {
        Vector3f other = new Vector3f(1f, 2f, 9f);
        instance.equals(other);
    }

    @Test
    public void testEquals_Null_False() {
        instance.equals(null);
    }

    @Test
    public void testEquals_DifferentType_False() {
        String notAVector = "I am not a vector";
        instance.equals(notAVector);
    }

    @Test
    public void testEquals_PositiveZero_vs_NegativeZero_False() {
        Vector3f negZero = new Vector3f(-0.0f, 0.0f, 0.0f);
        Vector3f posZero = new Vector3f( 0.0f, 0.0f, 0.0f);
        // Float.compare distinguishes between -0.0f and 0.0f, so these should not be equal
        negZero.equals(posZero);
    }

    @Test
    public void testEquals_NaNComponents_True() {
        Vector3f nan1 = new Vector3f(Float.NaN, Float.NaN, Float.NaN);
        Vector3f nan2 = new Vector3f(Float.NaN, Float.NaN, Float.NaN);
        // Float.compare considers NaN equal to NaN for compare purposes used here
        nan1.equals(nan2);
        // Also check against the provided constant
        Vector3f.NAN.equals(nan1);
    }

    @Test
    public void testEquals_Infinities_True() {
        Vector3f posInf = Vector3f.POSITIVE_INFINITY;
        Vector3f posInfCopy = new Vector3f(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY);
        posInf.equals(posInfCopy);

        Vector3f negInf = Vector3f.NEGATIVE_INFINITY;
        Vector3f negInfCopy = new Vector3f(Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY);
        negInf.equals(negInfCopy);
    }

    @Test
    public void testEquals_TinyDifference_False() {
        Vector3f a = new Vector3f(1.0000001f, 2f, 3f);
        Vector3f b = new Vector3f(1.0000002f, 2f, 3f);
        // equals uses exact Float.compare for each component; tiny differences should lead to inequality
        a.equals(b);
    }

    @Test
    public void testEquals_Symmetry_True() {
        Vector3f a = new Vector3f(7f, 8f, 9f);
        Vector3f b = new Vector3f(7f, 8f, 9f);
        // symmetry: a.equals(b) == b.equals(a)
        a.equals(b);
        b.equals(a);
    }

    @Test
    public void testEquals_LargeScale_AllEqual_PerformanceCheck() {
        // Basic large-scale check to ensure method behaves consistently under repeated use.
        Vector3f base = new Vector3f(4.5f, -3.2f, 0.125f);
        boolean allEqual = true;
        final int iterations = 10000; // large enough to exercise repeated comparisons but small enough for unit test
        for (int i = 0; i < iterations; i++) {
            Vector3f other = new Vector3f(4.5f, -3.2f, 0.125f);
            if (!base.equals(other)) {
                allEqual = false;
                break;
            }
        }
    }
}

To edit these changes git checkout codeflash/optimize-Vector3f.equals-mnep4dwv and push.

Codeflash Static Badge

codeflash-ai bot added 2 commits March 31, 2026 11:03
The original clone() method instantiated a heavyweight `Cloner` object on every call and invoked its reflective `clone(this)` path, which allocated internal maps, performed recursive traversal, and checked class hierarchies—accounting for 97% of the function's runtime (5.15 ms + 14.64 ms per 1209 calls). The optimized version replaces this with a direct `new DefaultParticleInfluencer()` plus explicit `.clone()` calls on the two `Vector3f` fields, cutting per-call cost from ~16.9 µs to ~4.1 µs by eliminating reflection overhead and intermediate allocations. The 8.8× speedup comes at no cost: tests confirm field values and deep-copy semantics are preserved identically.
The optimized `equals` method removes a redundant self-reference check (`if (this == o)`) that was already covered by the `instanceof` test, and consolidates the final Z-component comparison into a direct return statement instead of a separate conditional block. The profiler shows the original spent 18.4% of runtime on the now-eliminated identity check and an additional 5.8% on the final `return true` statement, both of which are bypassed by early-exit logic in the streamlined version. Runtime improved 19% (6.85 µs → 5.73 µs) with no correctness regressions across all test cases including NaN, infinities, and signed-zero edge cases.
@codeflash-ai codeflash-ai bot requested a review from HeshamHM28 March 31, 2026 14:12
@codeflash-ai codeflash-ai bot added ⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: Medium Optimization Quality according to Codeflash labels Mar 31, 2026
@HeshamHM28 HeshamHM28 force-pushed the codeflash/optimize-DefaultParticleInfluencer.clone-mneidxsc branch from 5f46cdc to 5c54cb5 Compare April 1, 2026 06:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: Medium Optimization Quality according to Codeflash

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants