Redis Zset and Double Precision: A Study on x86_64
Abstract
Redis Zset, a sorted set data structure, relies heavily on double precision floating-point numbers to store scores. However, due to the limitations of the double data type, scores exceeding 1.8e+18 will not yield the desired value. In this study, we investigate the behavior of Redis Zset on x86_64 architecture and explore the implications of using double precision floating-point numbers.
Introduction
Redis Zset is a sorted set data structure that stores elements with associated scores. The scores are used to determine the order of the elements in the set. In Redis, scores are stored as double precision floating-point numbers. However, the double data type has a maximum value of 1.8e+18, which is a limitation that can lead to unexpected results.
Redis Version and Zset Configuration
We used Redis version 5.0.4 for our experiments. The Zset was configured to store scores as double precision floating-point numbers using the zadd command.
Double Precision Floating-Point Numbers
Double precision floating-point numbers have a maximum value of 1.8e+18, which is 17 digits and 54 bits in binary. However, the strtod function, used to convert string representations of double precision floating-point numbers to actual values, will return a value of 1.8e+18 for any input exceeding this limit.
Code Snippets
The zzlGetScore function in Redis is responsible for retrieving the score of an element from a Zset:
unsigned char * vstr;
unsigned int vlen;
long long vlong;
char buf [128];
double score;
serverAssert (sptr = NULL!);
serverAssert (ziplistGet (sptr, & vstr, & vlen, & vlong));
if (vstr) {
memcpy (buf, vstr, vlen);
buf [vlen] = '\0';
score = strtod (buf, NULL); // convert string to double
} else {
score = vlong;
}
return score;
The addReplyDouble function is responsible for adding a double value as a bulk reply:
void addReplyDouble (client * c, double d) {
char dbuf [128], sbuf [128];
int dlen, slen;
if (isinf (d)) {
addReplyBulkCString (c, d > 0 ? "inf" : "-inf");
} else {
dlen = snprintf (dbuf, sizeof (dbuf), "% 17g.", d);
slen = snprintf (sbuf, sizeof (sbuf), "$%d \r\n% s \r\n", dlen, dbuf);
addReplyString (c, sbuf, slen);
}
}
Experimental Results
We conducted experiments on x86_64 architecture using the following commands:
127.0.0.1:6379> del k1
127.0.0.1:6379> zadd k1 18014398509481982 m1
127.0.0.1:6379> zrange k1 0 -1 WITHSCORES
1) "m1"
2) "18014398509481982"
The results show that the score is correctly retrieved as 1.8e+18.
However, when we try to add a score exceeding 1.8e+18:
127.0.0.1:6379> zadd k1 18014398509481983 m1
127.0.0.1:6379> zrange k1 0 -1 WITHSCORES
1) "m1"
2) "18014398509481984"
The score is incorrectly retrieved as 1.8e+18.
Conclusion
In conclusion, the use of double precision floating-point numbers in Redis Zset on x86_64 architecture can lead to unexpected results when scores exceed 1.8e+18. While the strtod function is used to convert string representations of double precision floating-point numbers to actual values, it will return a value of 1.8e+18 for any input exceeding this limit.
Annex: C/C++ Floating Point Knowledge Map
This paper was made possible with the support of Tencent Cloud’s media-sharing plan. We invite readers to join and share their knowledge on floating point numbers.
Published on
2019-05-10
Redis Storage Report
70 shares
Share article to a circle of friends
Share article on Twitter
Copy the link to the article to clipboard
Scan QR code
Community concerns cloud scan code + Tencent cloud receive vouchers