This is an automated email from the ASF dual-hosted git repository.

garydgregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-lang.git

commit 45db2840b0d7a4ed23b0659343f0a388eb2bb78e
Author: Gary Gregory <[email protected]>
AuthorDate: Sun Apr 26 19:02:32 2026 -0400

    Add NumberUtilsBenchmark
    
    See https://github.com/apache/commons-lang/pull/1628
---
 .../commons/lang3/math/NumberUtilsBenchmark.java   | 210 +++++++++++++++++++++
 1 file changed, 210 insertions(+)

diff --git 
a/src/test/java/org/apache/commons/lang3/math/NumberUtilsBenchmark.java 
b/src/test/java/org/apache/commons/lang3/math/NumberUtilsBenchmark.java
new file mode 100644
index 000000000..07b2dcfdc
--- /dev/null
+++ b/src/test/java/org/apache/commons/lang3/math/NumberUtilsBenchmark.java
@@ -0,0 +1,210 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.lang3.math;
+
+import java.util.concurrent.TimeUnit;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Fork;
+import org.openjdk.jmh.annotations.Measurement;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.Warmup;
+
+/**
+ * {@link NumberUtils#createNumber(String)} See 
https://github.com/apache/commons-lang/pull/1628
+ *
+ * <pre>
+ * mvn test -P benchmark -Dbenchmark=NumberUtilsBenchmark -P '!jacoco'
+ * </pre>
+ * Results on my machine on 2026-04-26:
+ // @formatter:off
+ * <pre>
+# JMH version: 1.37
+# VM version: JDK 21.0.11, OpenJDK 64-Bit Server VM, 21.0.11
+# VM invoker: 
/opt/homebrew/Cellar/openjdk@21/21.0.11/libexec/openjdk.jdk/Contents/Home/bin/java
+# VM options: <none>
+# Blackhole mode: compiler (auto-detected, use 
-Djmh.blackhole.autoDetect=false to disable)
+# Warmup: 3 iterations, 10 s each
+# Measurement: 5 iterations, 10 s each
+# Timeout: 10 min per iteration
+# Threads: 1 thread, will synchronize iterations
+# Benchmark mode: Average time, time/op
+# Benchmark: 
org.apache.commons.lang3.math.NumberUtilsBenchmark.testDefaultCheck
+
+# Run progress: 0.00% complete, ETA 00:08:00
+# Fork: 1 of 3
+# Warmup Iteration   1: 33.679 ns/op
+# Warmup Iteration   2: 32.796 ns/op
+# Warmup Iteration   3: 33.406 ns/op
+Iteration   1: 33.474 ns/op
+Iteration   2: 33.479 ns/op
+Iteration   3: 33.301 ns/op
+Iteration   4: 33.691 ns/op
+Iteration   5: 33.523 ns/op
+
+# Run progress: 16.67% complete, ETA 00:06:40
+# Fork: 2 of 3
+# Warmup Iteration   1: 33.716 ns/op
+# Warmup Iteration   2: 33.370 ns/op
+# Warmup Iteration   3: 33.073 ns/op
+Iteration   1: 33.057 ns/op
+Iteration   2: 33.076 ns/op
+Iteration   3: 32.987 ns/op
+Iteration   4: 33.102 ns/op
+Iteration   5: 33.060 ns/op
+
+# Run progress: 33.33% complete, ETA 00:05:20
+# Fork: 3 of 3
+# Warmup Iteration   1: 34.668 ns/op
+# Warmup Iteration   2: 33.436 ns/op
+# Warmup Iteration   3: 33.182 ns/op
+Iteration   1: 33.022 ns/op
+Iteration   2: 33.164 ns/op
+Iteration   3: 33.171 ns/op
+Iteration   4: 33.050 ns/op
+Iteration   5: 33.126 ns/op
+
+
+Result "org.apache.commons.lang3.math.NumberUtilsBenchmark.testDefaultCheck":
+  33.219 ±(99.9%) 0.235 ns/op [Average]
+  (min, avg, max) = (32.987, 33.219, 33.691), stdev = 0.220
+  CI (99.9%): [32.984, 33.454] (assumes normal distribution)
+
+
+# JMH version: 1.37
+# VM version: JDK 21.0.11, OpenJDK 64-Bit Server VM, 21.0.11
+# VM invoker: 
/opt/homebrew/Cellar/openjdk@21/21.0.11/libexec/openjdk.jdk/Contents/Home/bin/java
+# VM options: <none>
+# Blackhole mode: compiler (auto-detected, use 
-Djmh.blackhole.autoDetect=false to disable)
+# Warmup: 3 iterations, 10 s each
+# Measurement: 5 iterations, 10 s each
+# Timeout: 10 min per iteration
+# Threads: 1 thread, will synchronize iterations
+# Benchmark mode: Average time, time/op
+# Benchmark: 
org.apache.commons.lang3.math.NumberUtilsBenchmark.testShortcircuitCheck
+
+# Run progress: 50.00% complete, ETA 00:04:00
+# Fork: 1 of 3
+# Warmup Iteration   1: 0.587 ns/op
+# Warmup Iteration   2: 0.586 ns/op
+# Warmup Iteration   3: 0.586 ns/op
+Iteration   1: 0.586 ns/op
+Iteration   2: 0.586 ns/op
+Iteration   3: 0.586 ns/op
+Iteration   4: 0.586 ns/op
+Iteration   5: 0.586 ns/op
+
+# Run progress: 66.67% complete, ETA 00:02:40
+# Fork: 2 of 3
+# Warmup Iteration   1: 0.627 ns/op
+# Warmup Iteration   2: 0.586 ns/op
+# Warmup Iteration   3: 0.587 ns/op
+Iteration   1: 0.586 ns/op
+Iteration   2: 0.629 ns/op
+Iteration   3: 0.586 ns/op
+Iteration   4: 0.585 ns/op
+Iteration   5: 0.587 ns/op
+
+# Run progress: 83.33% complete, ETA 00:01:20
+# Fork: 3 of 3
+# Warmup Iteration   1: 0.628 ns/op
+# Warmup Iteration   2: 0.586 ns/op
+# Warmup Iteration   3: 0.587 ns/op
+Iteration   1: 0.587 ns/op
+Iteration   2: 0.587 ns/op
+Iteration   3: 0.621 ns/op
+Iteration   4: 0.624 ns/op
+Iteration   5: 0.587 ns/op
+
+
+Result 
"org.apache.commons.lang3.math.NumberUtilsBenchmark.testShortcircuitCheck":
+  0.594 ±(99.9%) 0.017 ns/op [Average]
+  (min, avg, max) = (0.585, 0.594, 0.629), stdev = 0.016
+  CI (99.9%): [0.577, 0.611] (assumes normal distribution)
+
+
+# Run complete. Total time: 00:08:01
+
+REMEMBER: The numbers below are just data. To gain reusable insights, you need 
to follow up on
+why the numbers are the way they are. Use profilers (see -prof, -lprof), 
design factorial
+experiments, perform baseline and negative tests that provide experimental 
control, make sure
+the benchmarking environment is safe on JVM/OS/HW level, ask for reviews from 
the domain experts.
+Do not assume the numbers tell you what you want them to tell.
+
+NOTE: Current JVM experimentally supports Compiler Blackholes, and they are in 
use. Please exercise
+extra caution when trusting the results, look into the generated code to check 
the benchmark still
+works, and factor in a small probability of new VM bugs. Additionally, while 
comparisons between
+different JVMs are already problematic, the performance difference caused by 
different Blackhole
+modes can be very significant. Please make sure you use the consistent 
Blackhole mode for comparisons.
+
+Benchmark                                   Mode  Cnt   Score   Error  Units
+NumberUtilsBenchmark.testDefaultCheck       avgt   15  33.219 ± 0.235  ns/op
+NumberUtilsBenchmark.testShortcircuitCheck  avgt   15   0.594 ± 0.017  ns/op
+
+Benchmark result is saved to target/jmh-result.NumberUtilsBenchmark.json
+ * </pre>
+ // @formatter:on
+ */
+@BenchmarkMode(Mode.AverageTime)
+@OutputTimeUnit(TimeUnit.NANOSECONDS)
+@State(Scope.Thread)
+@Fork(3)
+@Warmup(iterations = 3)
+@Measurement(iterations = 5)
+public class NumberUtilsBenchmark {
+
+    private static boolean isAllZeros(final String str) {
+        if (str == null) {
+            return true;
+        }
+        for (int i = str.length() - 1; i >= 0; i--) {
+            if (str.charAt(i) != '0') {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private static boolean isZero(final String mant, final String dec) {
+        return isAllZeros(mant) && isAllZeros(dec);
+    }
+
+    private final String str = "0.25";
+
+    private final String mant = "0";
+
+    private final String dec = "25";
+
+    Float f = Float.valueOf(str);
+
+    Double d = Double.valueOf(str);
+
+    @Benchmark
+    public boolean testDefaultCheck() {
+        return !f.isInfinite() && !(f.floatValue() == 0.0F && !isZero(mant, 
dec)) && f.toString().equals(d.toString());
+    }
+
+    @Benchmark
+    public boolean testShortcircuitCheck() {
+        return !f.isInfinite() && !(f.floatValue() == 0.0F && !isZero(mant, 
dec)) && (d.floatValue() == d.doubleValue() || 
f.toString().equals(d.toString()));
+    }
+}

Reply via email to