From 92c5ab40295260352f0da09616ff15b499251bad Mon Sep 17 00:00:00 2001 From: antirez Date: Tue, 2 Dec 2014 18:19:30 +0100 Subject: Use exp format and more precision output for ZSCAN. Ref: issue #2175 --- src/db.c | 2 +- src/object.c | 28 +++++++++++++++++----------- src/redis.h | 2 +- src/t_hash.c | 2 +- src/t_string.c | 2 +- 5 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/db.c b/src/db.c index d5a381daf..2982c0166 100644 --- a/src/db.c +++ b/src/db.c @@ -381,7 +381,7 @@ void scanCallback(void *privdata, const dictEntry *de) { } else if (o->type == REDIS_ZSET) { key = dictGetKey(de); incrRefCount(key); - val = createStringObjectFromLongDouble(*(double*)dictGetVal(de)); + val = createStringObjectFromLongDouble(*(double*)dictGetVal(de),0); } else { redisPanic("Type not handled in SCAN callback."); } diff --git a/src/object.c b/src/object.c index 6b8e42477..2b2d463f6 100644 --- a/src/object.c +++ b/src/object.c @@ -109,9 +109,11 @@ robj *createStringObjectFromLongLong(long long value) { return o; } -/* Note: this function is defined into object.c since here it is where it - * belongs but it is actually designed to be used just for INCRBYFLOAT */ -robj *createStringObjectFromLongDouble(long double value) { +/* Create a string object from a long double. If humanfriendly is non-zero + * it does not use exponential format and trims trailing zeroes at the end, + * however this result in loss of precision. Otherwise exp format is used + * and the output of snprintf() is not modified. */ +robj *createStringObjectFromLongDouble(long double value, int humanfriendly) { char buf[256]; int len; @@ -120,15 +122,19 @@ robj *createStringObjectFromLongDouble(long double value) { * that is "non surprising" for the user (that is, most small decimal * numbers will be represented in a way that when converted back into * a string are exactly the same as what the user typed.) */ - len = snprintf(buf,sizeof(buf),"%.17Lf", value); - /* Now remove trailing zeroes after the '.' */ - if (strchr(buf,'.') != NULL) { - char *p = buf+len-1; - while(*p == '0') { - p--; - len--; + if (humanfriendly) { + len = snprintf(buf,sizeof(buf),"%.17Lf", value); + /* Now remove trailing zeroes after the '.' */ + if (strchr(buf,'.') != NULL) { + char *p = buf+len-1; + while(*p == '0') { + p--; + len--; + } + if (*p == '.') len--; } - if (*p == '.') len--; + } else { + len = snprintf(buf,sizeof(buf),"%.17Lg", value); } return createStringObject(buf,len); } diff --git a/src/redis.h b/src/redis.h index 855ae5742..5b1b33a84 100644 --- a/src/redis.h +++ b/src/redis.h @@ -1116,7 +1116,7 @@ robj *tryObjectEncoding(robj *o); robj *getDecodedObject(robj *o); size_t stringObjectLen(robj *o); robj *createStringObjectFromLongLong(long long value); -robj *createStringObjectFromLongDouble(long double value); +robj *createStringObjectFromLongDouble(long double value, int humanfriendly); robj *createListObject(void); robj *createZiplistObject(void); robj *createSetObject(void); diff --git a/src/t_hash.c b/src/t_hash.c index f5ceb36e9..7f33bba0c 100644 --- a/src/t_hash.c +++ b/src/t_hash.c @@ -565,7 +565,7 @@ void hincrbyfloatCommand(redisClient *c) { } value += incr; - new = createStringObjectFromLongDouble(value); + new = createStringObjectFromLongDouble(value,1); hashTypeTryObjectEncoding(o,&c->argv[2],NULL); hashTypeSet(o,c->argv[2],new); addReplyBulk(c,new); diff --git a/src/t_string.c b/src/t_string.c index 74c05793c..e3c1e5f4a 100644 --- a/src/t_string.c +++ b/src/t_string.c @@ -397,7 +397,7 @@ void incrbyfloatCommand(redisClient *c) { addReplyError(c,"increment would produce NaN or Infinity"); return; } - new = createStringObjectFromLongDouble(value); + new = createStringObjectFromLongDouble(value,1); if (o) dbOverwrite(c->db,c->argv[1],new); else -- cgit v1.2.1