Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BigDecimal: Replace ==ZERO by isZero, ~40% time reduction on main methods #301

Merged
merged 1 commit into from
Jul 14, 2024

Conversation

glureau
Copy link
Contributor

@glureau glureau commented Jun 11, 2024

Replacing == ZERO by isZero() on BigDecimal class.

Motivation

equals method calls BD.compare(BD) which requires to bring the significant to same exponent before comparing (if either exponent or precision are not equals). This calculation go through getRidOfRadix and numberOfDecimalDigits which is in total quite expansive.

Metrics

As I've seen in #299 and #300, optimization gains are relatively similar no matter the platform. To save some time I'll only use JVM (the quickest) to benchmark all public methods directly involving the '== ZERO'. (Don't hesitate to ask me for more benchmarks if you think it's risky.)

Benchmark (JVM)

Best of 3 runs, 1000000 iterations each, M3 Pro with 36GB RAM, duration in ms

Method BEFORE AFTER % time reduction
subtract 395 219 44%
add 287 164 43%
pow 269 153 43%
hashCode 202 66 67%
add(ZERO) 79 20 75%
toStringExpanded 167 110 34%

Benchmark code

    @Test
    fun perfAddZero() {
        val bd = BigDecimal.parseString("123")
        val duration = measureTime {
            repeat(1_000_000) { bd + BigDecimal.ZERO }
        }
        println("add(ZERO): $duration")
    }

    @Test
    fun perfAdd() {
        val a = BigDecimal.parseString("123")
        val b = BigDecimal.parseString("34.56")
        val duration = measureTime {
            repeat(1_000_000) { a + b }
        }
        println("add: $duration")
    }

    @Test
    fun perfSubtract() {
        val a = BigDecimal.parseString("123")
        val b = BigDecimal.parseString("34.56")
        val duration = measureTime {
            repeat(1_000_000) { a - b }
        }
        println("subtract: $duration")
    }

    @Test
    fun perfHashCode() {
        val bd = BigDecimal.parseString("123.45")
        val duration = measureTime {
            // hashCode uses removeTrailingZeroes
            repeat(1_000_000) { bd.hashCode() }
        }
        println("hashCode: $duration")
    }

     @Test
    fun perfPow() {
        val bd = BigDecimal.parseString("123.45")
        val duration = measureTime {
            repeat(1_000_000) { bd.pow(3) }
        }
        println("pow: $duration")
    }

     @Test
    fun perfToStringExpanded() {
        val bd = BigDecimal.parseString("123.45")
        val duration = measureTime {
            repeat(1_000_000) { bd.toStringExpanded() }
        }
        println("toStringExpanded: $duration")
    }

Raw data

Before

Run 1
subtract: 395.261291ms
add: 288.861958ms
pow: 282.718375ms
hashCode: 212.823917ms
add(ZERO): 93.253209ms
toStringExpanded: 167.068250ms

Run 2
subtract: 397.731ms
add: 312.411208ms
pow: 269.341042ms
hashCode: 206.681333ms
add(ZERO): 78.573125ms
toStringExpanded: 167.801541ms

Run 3
subtract: 394.628875ms
add: 286.920209ms
pow: 279.920042ms
hashCode: 202.090084ms
add(ZERO): 79.048292ms
toStringExpanded: 176.490833ms

After

Run 1
subtract: 225.815875ms
add: 163.852750ms
pow: 155.257792ms
hashCode: 67.060416ms
add(ZERO): 20.868541ms
toStringExpanded: 117.800792ms

Run 2
subtract: 229.606292ms
add: 196.132167ms
pow: 153.424542ms
hashCode: 66.612959ms
add(ZERO): 19.638667ms
toStringExpanded: 109.715250ms

Run 3
subtract: 219.301333ms
add: 187.846375ms
pow: 157.756ms
hashCode: 66.152625ms
add(ZERO): 20.008958ms
toStringExpanded: 111.473625ms

@ionspin ionspin merged commit 952c28a into ionspin:main Jul 14, 2024
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants