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<[email protected]>
Sent: Sunday, December 14, 2025 18:23
To: Raffaello Giulietti
Cc:[email protected]
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 
<[email protected]<mailto:[email protected]>> 于 
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 <[email protected]<mailto:[email protected]>> 
on behalf of Memory <[email protected]<mailto:[email protected]>>
Sent: Sunday, December 14, 2025 09:45
To:[email protected]<mailto:[email protected]>
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

Reply via email to