Asking multiple AI to optimise the same code
As different AIs are implemented differently, they don't all provide the same answer, nor do they consistently outperform one another. The best approach is to use multiple AI and pick the one you like best.
My goal here is not to declare a winner based on one example, but instead to show the variety of answers you can get with different AI.
I asked each AI to
However, this model took 10 minutes, which isn't always worth the wait.
In this case, both GitHub Copilot and Microsoft Copilot gave the same answer.
HOT TAKE It worries me when people say they are using Co-pilot a lot and it makes a big difference, because apart from it's convinence, it's not great IMHO.
For the best outcome for you, I recommend learning from each and writing it from scratch yourself. If you just copy-and-paste the answers you aren't thinking about it and probably deskilling yourself in the process.
My goal here is not to declare a winner based on one example, but instead to show the variety of answers you can get with different AI.
I asked each AI to
Suggest how to implement this more optimally private static String formatOffset(int millis) { String sign = millis < 0 ? "-" : "+"; int saveSecs = Math.abs(millis) / 1000; int hours = saveSecs / 3600; int mins = ((saveSecs / 60) % 60); int secs = (saveSecs % 60); if (secs == 0) { if (mins == 0) { return sign + twoDigitString(hours); } return sign + twoDigitString(hours) + twoDigitString(mins); } return sign + twoDigitString(hours) + twoDigitString(mins) + twoDigitString(secs); } private static String twoDigitString(int value) { return Integer.toString(value + 100).substring(1); }
Gemini 2.5 pro
While Gemini is often my first go-to AI when I have a large code base, it's not the smartest. It does have a large context window, which means I can dump a large context into it without much thought on my part. However, if you have less than about 6,000 lines of context, you might find that o3-pro, o4-mini-high, or Claude 4 gives a better answer. In this case, it offered in about 10 seconds;private static String formatOffset(int millis) { long totalSeconds = Math.abs((long) millis / 1000); long hours = totalSeconds / 3600; long minutes = (totalSeconds % 3600) / 60; long seconds = totalSeconds % 60; StringBuilder sb = new StringBuilder(); sb.append(millis < 0 ? "-" : "+"); sb.append(String.format("%02d", hours)); if (minutes > 0 || seconds > 0) { sb.append(String.format(":%02d", minutes)); } if (seconds > 0) { sb.append(String.format(":%02d", seconds)); } return sb.toString(); }Not only is this approach slower, but it also fails to achieve the same result, which is even worse. The original format is +HHMMSS without a colon.
OpenAI o3-pro
This is both faster and correct. I couldn't say whether this is faster or slower than Claude's answer without benchmarking it.However, this model took 10 minutes, which isn't always worth the wait.
private static final String[] TWO_DIGIT = new String[60]; static { for (int i = 0; i < TWO_DIGIT.length; i++) { TWO_DIGIT[i] = (i < 10 ? "0" : "") + i; } } static String formatOffset(int millis) { int totalSecs = millis / 1_000; int abs = Math.abs(totalSecs); int hours = abs / 3_600; int minutes = (abs / 60) % 60; int seconds = abs % 60; StringBuilder sb = new StringBuilder(7); // max “+HHMMSS” sb.append(totalSecs < 0 ? '-' : '+') .append(TWO_DIGIT[hours]); if (seconds != 0 || minutes != 0) { sb.append(TWO_DIGIT[minutes]); if (seconds != 0) sb.append(TWO_DIGIT[seconds]); } return sb.toString(); // single String allocation here }
o4-mini-high
This code is faster than the original and correct, and it only took 9 seconds compared to o3-pro 10 minutes...private static String formatOffset(int millis) { long totalSecs = Math.abs((long) millis) / 1_000; int hours = (int) (totalSecs / 3_600); int remainder = (int) (totalSecs - hours * 3_600); int mins = remainder / 60; int secs = remainder - mins * 60; // Determine length: 1 for sign, 2 for HH, +2 for MM if needed, +2 for SS if needed int len = 1 + 2 + ((mins != 0 || secs != 0) ? 2 : 0) + ((secs != 0) ? 2 : 0); char[] buf = new char[len]; int pos = 0; buf[pos++] = millis < 0 ? '-' : '+'; buf[pos++] = (char) ('0' + hours / 10); buf[pos++] = (char) ('0' + hours % 10); if (mins != 0 || secs != 0) { buf[pos++] = (char) ('0' + mins / 10); buf[pos++] = (char) ('0' + mins % 10); if (secs != 0) { buf[pos++] = (char) ('0' + secs / 10); buf[pos++] = (char) ('0' + secs % 10); } } return new String(buf); }
Claude 4
This is one of the better answers. I use Claude as a third opinion, as I prefer the answers for o3-pro/o4-mini-high or the larger context window of Gemini 2.5 pro.private static String formatOffset(int millis) { char[] buffer = new char[7]; // Max length: +HHMMSS int pos = 0; // Handle sign if (millis < 0) { buffer[pos++] = '-'; millis = -millis; } else { buffer[pos++] = '+'; } int totalSecs = millis / 1000; int hours = totalSecs / 3600; int mins = (totalSecs % 3600) / 60; int secs = totalSecs % 60; // Always include hours buffer[pos++] = (char) ('0' + hours / 10); buffer[pos++] = (char) ('0' + hours % 10); if (mins != 0 || secs != 0) { buffer[pos++] = (char) ('0' + mins / 10); buffer[pos++] = (char) ('0' + mins % 10); if (secs != 0) { buffer[pos++] = (char) ('0' + secs / 10); buffer[pos++] = (char) ('0' + secs % 10); } } return new String(buffer, 0, pos); }
Grok 3 Think
Grok 4 is widely considered to be much better; however, I haven't started subscribing to it yet. It's similar to Gemini in this case, without the introduced bug.private static String formatOffset(int millis) { // Determine the sign and work with absolute value String sign = millis < 0 ? "-" : "+"; int absMillis = Math.abs(millis); // Directly calculate hours, minutes, and seconds int hours = absMillis / 3600000; // 3600000 ms = 1 hour int minutes = (absMillis % 3600000) / 60000; // 60000 ms = 1 minute int seconds = (absMillis % 60000) / 1000; // 1000 ms = 1 second // Build the result efficiently using StringBuilder StringBuilder sb = new StringBuilder(); sb.append(sign); sb.append(String.format("%02d", hours)); // Include minutes and seconds based on their values if (minutes > 0 || seconds > 0) { sb.append(String.format("%02d", minutes)); if (seconds > 0) { sb.append(String.format("%02d", seconds)); } } return sb.toString(); }
Copilot
I use Github Copilot in my IDE for simplicity, rarely using the Microsoft Copilot except for curiosity's sake. It's generally worse than the other options I have tried.In this case, both GitHub Copilot and Microsoft Copilot gave the same answer.
private static String formatOffset(int millis) { Duration d = Duration.ofMillis(millis); long totalSecs = d.getSeconds(); long absSecs = Math.abs(totalSecs); long hours = absSecs / 3600; int mins = (int) ((absSecs % 3600) / 60); int secs = (int) (absSecs % 60); char sign = totalSecs < 0 ? '-' : '+'; if (secs == 0) { return String.format("%c%02d:%02d", sign, hours, mins); } return String.format("%c%02d:%02d:%02d", sign, hours, mins, secs); }This has multiple bugs, and it's significantly slower.
HOT TAKE It worries me when people say they are using Co-pilot a lot and it makes a big difference, because apart from it's convinence, it's not great IMHO.
Conclusion
Particularly when it comes to non-idiomatic code, e.g. low-latency, AI can struggle as these might not be well represented in their training set. I find I spend the most time creating the prompt with the proper context, so copy-and-pasting the same prompt to multiple AI isn't a big deal, you can pick the answer you like or even combine the results.For the best outcome for you, I recommend learning from each and writing it from scratch yourself. If you just copy-and-paste the answers you aren't thinking about it and probably deskilling yourself in the process.
I wish we see some numbers here from JMH :)
ReplyDelete