Improving the prompt to the AI to get better code
In a previous article I looked at one-shoting a solution to optimise code to show the variation in different AI. Thsi is the not the best way to get what you want however. More often you need to either refine the prompt or give feedback. After one-shoting the same prompt on multiple AI, I have created a refined prompt based on the various concerns with previous results.
The prompt
Based on the results in a previous run Asking multiple AI to optimise the same code
Suggest how to implement this more optimally using low latency techniques
to minimize any objects created.
## Use
- a ThreadLocal for temporary data.
- simple maths rather than a library, add comments for clarity if needed.
- offset in the form ±hh, ±hhmm, or ±hhmmss, using the shortest form that
does not lose information, where hh, mm, and ss are the hours, minutes,
and seconds east (+) or west (-) of UT
- return a `intern()` String.
## Don't use
- String.format
- String operations that create objects.
- any colons, they aren't required
- reduce code duplication
## The code
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);
}
I typically use asciidoc rather than markdown, but trying to keep this example simple.
None of the AI considered using a byte[] event though String now uses a byte[] as an underlying store. I asked each one to
change the implementation to use a byte[] to create an ISO_8859_1 encoded stringwhich they were able to do, but none suggested it.
Gemini 2.5 pro
This result is signifciantly improved. Use use of StringBuilder is more idomatic, but adds overhead. I find Gemini tends to produce wordier results.
/**
* A ThreadLocal holding a StringBuilder instance for each thread.
* This avoids creating a new StringBuilder on each method call, reducing
* object churn and garbage collection pressure. The initial capacity is
* set to 7, the maximum length of the output string (e.g., "-hhmmss").
*/
private static final ThreadLocal<StringBuilder> OFFSET_BUILDER =
ThreadLocal.withInitial(() -> new StringBuilder(7));
/**
* Formats a timezone offset from milliseconds into the shortest possible
* ISO 8601 format (±hh, ±hhmm, or ±hhmmss).
*
* This implementation is optimized to minimize object creation by using a
* ThreadLocal StringBuilder and simple integer arithmetic.
*
* @param millis The offset from UTC in milliseconds.
* @return A string representation of the offset, fetched from the string pool.
*/
public static String formatOffset(int millis) {
// Get the reusable StringBuilder for the current thread and clear it.
StringBuilder sb = OFFSET_BUILDER.get();
sb.setLength(0);
// Determine the sign and work with absolute values.
final char sign = millis < 0 ? '-' : '+';
final int totalSeconds = Math.abs(millis) / 1000;
// Decompose the total seconds into hours, minutes, and seconds.
// 3600 seconds in an hour.
final int hours = totalSeconds / 3600;
// 60 seconds in a minute.
final int minutes = (totalSeconds / 60) % 60;
final int seconds = totalSeconds % 60;
// Append the sign character.
sb.append(sign);
// Append the hours, padded to two digits.
appendTwoDigits(sb, hours);
// Only include minutes and seconds if they are non-zero,
// using the shortest format possible.
if (minutes == 0 && seconds == 0) {
// Format is ±hh, so we are done.
return sb.toString().intern();
}
// Append the minutes, padded to two digits.
appendTwoDigits(sb, minutes);
if (seconds == 0) {
// Format is ±hhmm, so we are done.
return sb.toString().intern();
}
// Append the seconds, padded to two digits, for the ±hhmmss format.
appendTwoDigits(sb, seconds);
// Return the final string from the shared pool.
return sb.toString().intern();
}
/**
* Appends an integer value to a StringBuilder, padded with a leading zero
* if it is less than 10. This is a fast, object-free alternative to
* String.format or Integer.toString.
*
* @param sb The StringBuilder to append to.
* @param value The integer value (0-99).
*/
private static void appendTwoDigits(StringBuilder sb, int value) {
// By adding '0', we convert the integer result of the division/modulo
// into its ASCII character equivalent.
// Example for value=7: '0' + 0 = '0', '0' + 7 = '7' -> "07"
// Example for value=12: '0' + 1 = '1', '0' + 2 = '2' -> "12"
sb.append((char) ('0' + value / 10));
sb.append((char) ('0' + value % 10));
}
o3-pro
This took the longest, 18m 20s.
/** Thread‑local scratch – long enough for “-235959” (7 chars inc. sign) */
private static final ThreadLocal<char[]> BUF =
ThreadLocal.withInitial(() -> new char[7]);
/**
* Format an offset in milliseconds as ±hh[mm[ss]] with no separators.
* The returned String is interned so repeated calls for the same offset
* are pointer‑equal.
*/
public static String formatOffset(int millis) {
char[] buf = BUF.get();
int pos = 0;
// sign ---------------------------------------------------------------
if (millis < 0) {
buf[pos++] = '-';
millis = -millis; // safe: abs(Integer.MIN_VALUE) won’t hit here
} else {
buf[pos++] = '+';
}
// breakdown ---------------------------------------------------------
int totalSecs = millis / 1_000;
int hours = totalSecs / 3_600;
int minutes = (totalSecs / 60) % 60;
int seconds = totalSecs % 60;
pos = writeTwoDigits(buf, pos, hours);
if (minutes == 0 && seconds == 0)
return new String(buf, 0, pos).intern();
pos = writeTwoDigits(buf, pos, minutes);
if (seconds == 0)
return new String(buf, 0, pos).intern();
pos = writeTwoDigits(buf, pos, seconds);
return new String(buf, 0, pos).intern();
}
/** Writes exactly two ASCII digits into buf and returns new position. */
private static int writeTwoDigits(char[] buf, int pos, int value) {
buf[pos++] = (char) ('0' + value / 10);
buf[pos++] = (char) ('0' + value % 10);
return pos;
}
o4-mini-high
This soltuion is good but has more duplication than I would like. This took 17 seconds.
private static final ThreadLocal<char[]> OFFSET_BUF =
ThreadLocal.withInitial(() -> new char[7]); // sign + hh + mm + ss
/**
* Format a UTC offset in ±hh, ±hhmm or ±hhmmss (no colons),
* using the shortest form that contains all non-zero fields.
* Returns an interned String so each distinct offset is pooled.
*
* @param offsetMillis signed offset from UTC in milliseconds
* @return offset string, e.g. "+02", "-0530", "+023015"
*/
public static String formatOffset(int offsetMillis) {
char[] buf = OFFSET_BUF.get();
// Convert to total seconds and extract sign
int totalSecs = offsetMillis / 1000;
char sign = totalSecs < 0 ? '-' : '+';
if (totalSecs < 0) totalSecs = -totalSecs;
// Hours, minutes, seconds by simple div/mod math
int hours = totalSecs / 3600;
int rem = totalSecs - hours * 3600;
int minutes = rem / 60;
int seconds = rem - minutes * 60;
// Fill buffer
int pos = 0;
buf[pos++] = sign;
// always two digits for hours
buf[pos++] = (char)('0' + (hours / 10));
buf[pos++] = (char)('0' + (hours % 10));
if (seconds == 0) {
if (minutes == 0) {
// ±hh
return new String(buf, 0, pos).intern();
}
// ±hhmm
buf[pos++] = (char)('0' + (minutes / 10));
buf[pos++] = (char)('0' + (minutes % 10));
return new String(buf, 0, pos).intern();
}
// ±hhmmss
buf[pos++] = (char)('0' + (minutes / 10));
buf[pos++] = (char)('0' + (minutes % 10));
buf[pos++] = (char)('0' + (seconds / 10));
buf[pos++] = (char)('0' + (seconds % 10));
return new String(buf, 0, pos).intern();
}
Claude 4
The improved prompt improved the solution which was already pretty good. This took a 1m,40s.
// ThreadLocal buffer reused across calls to minimize object creation
private static final ThreadLocal<char[]> BUFFER = ThreadLocal.withInitial(() -> new char[7]);
private static String formatOffset(int millis) {
char[] buf = BUFFER.get();
int pos = 0;
// Add sign: + for positive/zero, - for negative
buf[pos++] = millis < 0 ? '-' : '+';
// Convert to positive seconds for calculations
int totalSeconds = Math.abs(millis) / 1000;
// Extract hours, minutes, seconds using simple division/modulo
int hours = totalSeconds / 3600; // 3600 seconds per hour
int mins = (totalSeconds / 60) % 60; // 60 seconds per minute, mod 60 for remainder
int secs = totalSeconds % 60; // Remaining seconds
// Hours are always included (±hh minimum format)
buf[pos++] = (char)('0' + hours / 10); // Tens digit
buf[pos++] = (char)('0' + hours % 10); // Units digit
// Include minutes if non-zero or if seconds are non-zero
if (mins != 0 || secs != 0) {
buf[pos++] = (char)('0' + mins / 10);
buf[pos++] = (char)('0' + mins % 10);
// Include seconds only if non-zero
if (secs != 0) {
buf[pos++] = (char)('0' + secs / 10);
buf[pos++] = (char)('0' + secs % 10);
}
}
// Create final string from buffer and intern for memory efficiency
return new String(buf, 0, pos).intern();
}
Grok 3 Think
This result is much better with a refined prompt. As noted before Grok 4 should be better. This took a 53 seconds.
// Size of 9 covers worst-case scenario: +hhmmss (7 chars) plus potential padding.
private static final ThreadLocal<char[]> BUFFER = ThreadLocal.withInitial(() -> new char[9]);
private static String formatOffset(int millis) {
// Use ThreadLocal char array to avoid StringBuilder or new String creation
char[] buf = BUFFER.get();
int pos = 0;
// Determine sign and absolute seconds
int absMillis = Math.abs(millis);
buf[pos++] = millis < 0 ? '-' : '+';
int totalSecs = absMillis / 1000;
// Calculate hours, minutes, seconds using division and modulo
int hours = totalSecs / 3600;
int remainingSecs = totalSecs % 3600;
int mins = remainingSecs / 60;
int secs = remainingSecs % 60;
// Convert hours to two digits
buf[pos++] = (char) ('0' + hours / 10);
buf[pos++] = (char) ('0' + hours % 10);
// Skip minutes and seconds if zero for shortest representation
if (mins == 0 && secs == 0) {
return new String(buf, 0, pos).intern();
}
// Append minutes
buf[pos++] = (char) ('0' + mins / 10);
buf[pos++] = (char) ('0' + mins % 10);
// Skip seconds if zero
if (secs == 0) {
return new String(buf, 0, pos).intern();
}
// Append seconds
buf[pos++] = (char) ('0' + secs / 10);
buf[pos++] = (char) ('0' + secs % 10);
return new String(buf, 0, pos).intern();
}
After being asked to use a byte[] it used a byte[9]
GitHub Copilot with GPT 4.1
This produced a much better result with the more detailed prompt. Note that it uses ±h instead of always using ±hh. This took a few seconds.
private static final ThreadLocal<char[]> OFFSET_BUFFER = ThreadLocal.withInitial(() -> new char[7]); // sign + 2*3 digits
private static String formatOffset(int millis) {
char[] buf = OFFSET_BUFFER.get();
int absMillis = millis < 0 ? -millis : millis;
int totalSecs = absMillis / 1000;
int hours = totalSecs / 3600;
int mins = (totalSecs / 60) % 60;
int secs = totalSecs % 60;
int pos = 0;
buf[pos++] = millis < 0 ? '-' : '+';
// Write hours
if (hours < 10) {
buf[pos++] = (char) ('0' + hours);
} else {
buf[pos++] = (char) ('0' + hours / 10);
buf[pos++] = (char) ('0' + hours % 10);
}
// Only add minutes if needed
if (mins != 0 || secs != 0) {
buf[pos++] = (char) ('0' + mins / 10);
buf[pos++] = (char) ('0' + mins % 10);
}
// Only add seconds if needed
if (secs != 0) {
buf[pos++] = (char) ('0' + secs / 10);
buf[pos++] = (char) ('0' + secs % 10);
}
// Return interned String
return new String(buf, 0, pos).intern();
}
Microsoft Copilot with Think Deeper
This is significantly better than the simple prompt. This took a few seconds.
public class OffsetFormatter {
// Thread-local buffer: max length 7 ("±hhmmss")
private static final ThreadLocal<char[]> BUF =
ThreadLocal.withInitial(() -> new char[7]);
/**
* Formats a UTC offset in milliseconds to a string in the form:
* ±hh, ±hhmm, or ±hhmmss using the shortest form
* without losing information. Returns an interned String.
*/
public static String formatOffset(int offsetMillis) {
char[] buf = BUF.get();
// 0: sign, 1–2: hh, 3–4: mm, 5–6: ss
buf[0] = offsetMillis < 0 ? '-' : '+';
// total seconds east of UT
int totalSeconds = Math.abs(offsetMillis) / 1000;
// compute hours / minutes / seconds
int hours = totalSeconds / 3600;
int rem = totalSeconds - hours * 3600;
int mins = rem / 60;
int secs = rem - mins * 60;
// write two-digit hours
writeTwoDigits(buf, 1, hours);
if (secs == 0) {
if (mins == 0) {
// ±hh
return new String(buf, 0, 3).intern();
}
// write two-digit minutes (±hhmm)
writeTwoDigits(buf, 3, mins);
return new String(buf, 0, 5).intern();
}
// write two-digit minutes and seconds (±hhmmss)
writeTwoDigits(buf, 3, mins);
writeTwoDigits(buf, 5, secs);
return new String(buf, 0, 7).intern();
}
/**
* Writes a zero-padded two-digit number into buf at position idx:
* buf[idx] = tens digit
* buf[idx+1] = ones digit
*/
private static void writeTwoDigits(char[] buf, int idx, int value) {
buf[idx] = (char) ('0' + (value / 10));
buf[idx+1] = (char) ('0' + (value % 10));
}
}
Conclusion
It's worth noting that;- None suggested using a byte[] though they could all do that.
- To reduce code duplication some uses a helper method or called new String once. None did both optimisations.
- The more detailed prompt helped the AI which gave poor answers before bridging the gap in the results.
- The AI which took significantly longer, didn't produce a significantly better answer in this case.
Comments
Post a Comment