自從去年ChatGPT3.5釋出後使用了幾次,現在寫程式碼基本上離不開它和它的衍生產品們了。一方面查資料很方便,快速提煉要點總結;另一方面想寫什麼樣的程式碼一問就能生成出來,功能大差不差,稍微改改就能用,大大減少使用搜尋引擎的時間,是新時代高階版的Ctrl+C/V。
不過大語言模型歸根揭底是靠訓練集訓練出來的,它給出的程式碼還是要自己測試一下用起來才放心,比如這次就被它坑了一把。
注:因種種原因,本文僅測試了一些國內的大語言模型,沒有測試ChatGPT。
原始需求
某列表查詢功能,入參包含一組起止日期,需要校驗起止日期跨度小於等於200天。
前端傳參現狀
將使用者選擇的起止日期(yyyy-MM-dd)轉換成"yyyy-MM-dd HH:mm:ss"格式的字串,且起始時間是"yyyy-MM-dd 00:00:00",終止時間是"yyyy-MM-dd 23:59:59"。
比如,頁面上選擇從2024-09-01到2024-09-30,實際的入參是"2024-09-01 00:00:00"和"2024-09-30 23:59:59"。而且對於這組引數,時間跨度是30天,也就是說包括首尾的當天。
需求簡化
為了便於測試,我先把時間跨度的要求改為2天,比如"2024-09-01 00:00:00"到"2024-09-02 23:59:59"的時間跨度正好是2天。需求可以簡化為:
String sendDateBegin="2024-09-01 00:00:00"
String sendDateEnd="2024-09-02 23:59:59"
Java程式碼判斷兩個天數是否小於等於2天
kimi給的結果:
程式碼提取出來:
public static void main(String[] args) {
String sendDateBegin = "2024-09-01 00:00:00";
String sendDateEnd = "2024-09-04 23:59:59";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime beginDate = LocalDateTime.parse(sendDateBegin, formatter);
LocalDateTime endDate = LocalDateTime.parse(sendDateEnd, formatter);
// 計算時間差
Duration duration = Duration.between(beginDate, endDate);
// 獲取天數差
long daysBetween = duration.toDays();
// 判斷天數是否小於等於2
if (daysBetween <= 2) {
System.out.println("兩個日期之間的天數小於或等於2天。");
} else {
System.out.println("兩個日期之間的天數超過2天。");
}
}
}
發現問題
使用2024-09-01 00:00:00~2024-09-02 23:59:59這組資料,返回結果如下,看上去一切正常:
換一組輸入2024-09-01 00:00:00~2024-09-03 23:59:59,居然也告訴我小於等於2天,是哪裡出現了問題?
分析
debug一下程式碼,發現duration.toDays()的實際處理方式是:
將兩個時間的秒數差,除以一天包含的秒數(86400),兩個引數都是long型。
那麼在這個例子裡,超過2天但不足3天的資料,由於long的除法,會將小數部分拋棄,再與2比較:2.999≈2,2≤2為true。這就是為什麼看似正確的程式碼實際引入了一個bug。
而且,即使提醒kimi這段程式碼有bug並告知對應的輸入,給出的答案仍然是錯的。
同樣的問題通義千問給了另一種解法,但是答案仍然是錯的:
再看看文心一言,半斤八兩:
解決
既然按天比較因為精度丟失而有誤差,那麼把日期轉成毫秒比較就不會丟失精度了,使用如下的判斷即可。
Duration.between(beginDate, endDate).toMillis() <= Duration.ofDays(2).toMillis();
這個例子生動的展示,寫程式碼不能完全依賴大語言模型,該做的測試還是要做的。當然,如果你把測試用例的編寫工作也交給了大語言模型,或許是能夠測出來bug的,挺諷刺的是不是?