[External] : Re: Question about potential optimization for Year.isLeap()
Roger Riggs
roger.riggs at oracle.com
Mon Dec 15 21:11:25 UTC 2025
Hi,
Leap year computation is well trodden ground. You might find Ben Joffe's
<https://www.benjoffe.com/fast-leap-year> article interesting among others.
There is also an amazing amount of optimization that occurs after the
code is written and
the compilation to different instruction sets is taken into account.
Some hardware techniques that come into play are:
- Branch prediction, in which the cpu pre-fetches both instruction
paths and in some cases speculatively executes down both paths, making a
late choice to pick the proper result.
- Conditional assignments in which there is no branch, just a register
load that is conditional on some previous condition.
- etc...
I'd expect to see different performance results on different
architectures. (x64, aarch64, etc).
Sometimes, its hard to pick which variant to leave in the source code.
Frequently, a good compromise is to make sure the algorithm is correct
and easy to understand and let the optimizer do its best.
Regards, Roger
On 12/15/25 2:55 PM, Raffaello Giulietti wrote:
> BTW, the variant below excluded 75% of the non-leap years with just one comparison:
> ```
> return (year & 0x3) == 0 && ((year & 0xF) == 0 || year % 100 != 0)
> ```
>
>
> ________________________________________
> From: Memory<smqy2314 at gmail.com>
> Sent: Sunday, December 14, 2025 18:23
> To: Raffaello Giulietti
> Cc:core-libs-dev at openjdk.org
> Subject: [External] : Re: Question about potential optimization for Year.isLeap()
>
> Hi,
>
> Thanks for the correction. I confused the implementations.
>
> I'm proposing to change:
>
> ```java
> return (year & 15) == 0 ? (year & 3) == 0 : (year & 3) == 0 && year % 100 != 0;
> ```
>
> to:
>
> ```java
> return (year & 15) == 0 || ((year & 3) == 0 && year % 100 != 0);
> ```
>
> At the low level, this should be slightly faster because:
>
> 1. Fewer CPU branches - Ternary creates a true branch, while logical operators use short-circuit evaluation
> 2. Better for branch prediction - Simpler control flow pattern
> 3. Less operation duplication - The current code conceptually checks (year & 3) == 0 twice in the false case
>
> However, I understand any performance difference would likely be minimal. If the team prefers the current ternary operator for better readability, I fully respect that decision.
>
> Raffaello Giulietti <raffaello.giulietti at oracle.com<mailto:raffaello.giulietti at oracle.com>> 于 2025年12月14日周日 19:45写道:
> Hi,
>
> the current logic in mainline is
> ```
> return (year & 15) == 0 ? (year & 3) == 0 : (year & 3) == 0 && year % 100 != 0;
> ```
> (seehttps://github.com/openjdk/jdk/blob/fb531cdaf3b30034e0efa86b9b20558478ce94d0/src/java.base/share/classes/java/time/Year.java#L321<https://urldefense.com/v3/__https://github.com/openjdk/jdk/blob/fb531cdaf3b30034e0efa86b9b20558478ce94d0/src/java.base/share/classes/java/time/Year.java*L321__;Iw!!ACWV5N9M2RV99hQ!ILBGqbgmHKbXqqdQShgtaBhShlZKl8_Pe_pvHC1yFBjQp2pUZrgcTzDZP6efKRPT8iVsh9IrxVmyRfl8LtnSiu_w$>)
>
>
> ________________________________________
> From: core-libs-dev <core-libs-dev-retn at openjdk.org<mailto:core-libs-dev-retn at openjdk.org>> on behalf of Memory <smqy2314 at gmail.com<mailto:smqy2314 at gmail.com>>
> Sent: Sunday, December 14, 2025 09:45
> To:core-libs-dev at openjdk.org<mailto:core-libs-dev at openjdk.org>
> Subject: Question about potential optimization for Year.isLeap()
>
> Hello core-libs-dev team,
>
> My name is Memory2314, and I am a new contributor currently waiting for my Oracle Contributor Agreement (OCA) to be processed.
>
> I have been studying the `java.time.Year.isLeap()` method and would like to propose a micro-optimization:
>
> **Current logic:**
> ```java
> return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
> ```
>
> **Proposed optimization:**
> ```java
> return (year & 15) == 0 || ((year & 3) == 0 && year % 100 != 0);
> ```
>
> **Key improvements:**
> - Replaces `year % 4 == 0` with bitwise `(year & 3) == 0`
> - Uses `(year & 15) == 0` to efficiently detect years divisible by 400
> - Reduces modulo operations from 3 to 1 in the common case
>
> **Verification benchmark:**
> ```java
> public static void main(String[] args) {
> int[] years = new int[1_000_000_000];
> Random random = new Random();
> for (int i = 0; i < years.length; i++) {
> years[i] = 1970 + random.nextInt(5000 - 1970 + 1);
> }
>
> long start1 = System.currentTimeMillis();
> for (int year : years) {
> boolean result = isLeapOriginal(year);
> }
> System.out.println("Original: " + (System.currentTimeMillis()-start1) + "ms");
>
> long start2 = System.currentTimeMillis();
> for (int year : years) {
> boolean result = isLeapOptimized(year);
> }
> System.out.println("Optimized: " + (System.currentTimeMillis()-start2) + "ms");
> }
>
> public static boolean isLeapOriginal(long year) {
> return (year & 15) == 0 ? (year & 3) == 0 : (year & 3) == 0 && year % 100 != 0;
> }
>
> public static boolean isLeapOptimized(long year) {
> return (year & 15) == 0 || ((year & 3) == 0 && year % 100 != 0);
> }
> ```
>
> **Correctness verification:** I've tested this logic extensively, including edge cases like year 0, negative years (proleptic Gregorian), and all century boundaries from -10,000 to 10,000.
>
> I am aware that I cannot submit a formal patch until my OCA is complete. However, I would be very grateful for your initial technical feedback on this approach before I proceed to create a fully tested patch with benchmarks.
>
> Once my OCA is in place, would there be a maintainer or an experienced contributor interested in sponsoring this change if it proves worthwhile?
>
> Thank you for your time and consideration.
>
> Best regards,
> Memory2314
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/core-libs-dev/attachments/20251215/5d3fc03c/attachment.htm>
More information about the core-libs-dev
mailing list