平臺:x86_64函數
結論:Zset的最大分數不要超過18014398509481982(17位數字,54位二進制),不然不會獲得指望的值。測試
REdis:5.0.4spa
Zset採用double存儲分數值(score),而incrbyfloat和hincrbyfloat採用的是long double存儲數值。orm
double自己是能夠存儲比18014398509481982(17位數字,54位二進制)大的值,好比18014398509481983(也是17位數字,54位二進制)。但REdis在返回結果時,調用strtod將值轉成double類型。server
取值源代碼:blog
double zzlGetScore(unsigned char *sptr) { // t_zset.c:722ip unsigned char *vstr;ci unsigned int vlen;字符串 long long vlong;it char buf[128]; double score;
serverAssert(sptr != NULL); serverAssert(ziplistGet(sptr,&vstr,&vlen,&vlong));
if (vstr) { memcpy(buf,vstr,vlen); buf[vlen] = '\0'; // 調用庫函數strtod, // 若是值小於18014398509481983,能獲得預期的值, // 不然老是返回18014398509481984(2的54次方)。 score = strtod(buf,NULL); // 字符串轉double } else { score = vlong; }
return score; } |
以字符串形式返回:
/* Add a double as a bulk reply */ void addReplyDouble(client *c, double d) { // networking.c:471 char dbuf[128], sbuf[128]; int dlen, slen; if (isinf(d)) { /* Libc in odd systems (Hi Solaris!) will format infinite in a * different way, so better to handle it in an explicit way. */ addReplyBulkCString(c, d > 0 ? "inf" : "-inf"); } else { dlen = snprintf(dbuf,sizeof(dbuf),"%.17g",d); // double轉字符串 slen = snprintf(sbuf,sizeof(sbuf),"$%d\r\n%s\r\n",dlen,dbuf); addReplyString(c,sbuf,slen); } } |
x86_64上的測試:
127.0.0.1:6379> del k1 (integer) 1 127.0.0.1:6379> zadd k1 18014398509481982 m1 (integer) 1 127.0.0.1:6379> zrange k1 0 -1 WITHSCORES 1) "m1" 2) "18014398509481982" 預期的值 127.0.0.1:6379> del k1 (integer) 1 127.0.0.1:6379> zadd k1 18014398509481983 m1 (integer) 1 127.0.0.1:6379> zrange k1 0 -1 WITHSCORES 1) "m1" 2) "18014398509481984" 非預期的值(和strtod相關)
127.0.0.1:6379> del k1 (integer) 1 127.0.0.1:6379> zadd k1 18014398509481982 m1 (integer) 1 127.0.0.1:6379> zrange k1 0 -1 WITHSCORES 1) "m1" 2) "18014398509481982" 預期的值 127.0.0.1:6379> zincrby k1 1 m1 "18014398509481984" 非預期的值 127.0.0.1:6379> zrange k1 0 -1 WITHSCORES 1) "m1" 2) "18014398509481984" 非預期的值 |
附:C/C++浮點知識圖譜