2021-10-22

标题redis中存储小数

原文链接

在做一个活动的需求时,需要往redis中有序的集合中存储一个小数,结果发现取出数据和存储时的数据不一致

复制代码
zadd test_2017 1.1 tom
(integer) 1
zrevrange test_2017 0 -1 withscores

  1. “tom”
  2. “1.1000000000000001”

zadd test_2017 1.2 sam
(integer) 1
zrevrange test_2017 0 -1 withscores

  1. “sam”
  2. “1.2”
  3. “tom”
  4. “1.1000000000000001”
    复制代码

是不是很奇怪, 存储tom的score 为1.1,结果为 1.1000000000000001,存储 sam的score为1.2,结果就是1.2

1.19999999999999995559 第16位是9,第17位是5, 四舍五入1.2

1.10000000000000008882 第16位是0, 第17位是8,四舍五入1.10000000000000001

但在php中

<?php echo 1.1; 确实显示1.1,是不是有点奇怪,后来在php.ini中找到到precision这个选项, 指 ; The number of significant digits displayed in floating point numbers. ; http://php.net/precision precision = 14 因为在php中,小数都是以double形式存储的,那么1.10000000000000008882中第14位为0,第15位也为0,四舍五入,为1.1 解决方法:php在处理时使用bcmul函数,将小数*100,再存入redis,待取出来时,再除以100 看了下redis zadd的源码,发现 zadd key score name 这个命令,redis利用strtod这个函数 将score 转为double浮点数 复制代码 /* This generic command implements both ZADD and ZINCRBY. */ void zaddGenericCommand(redisClient *c, int incr) { static char *nanerr = "resulting score is not a number (NaN)"; robj *key = c->argv[1]; robj *ele; robj *zobj; robj *curobj; double score = 0, *scores, curscore = 0.0; int j, elements = (c->argc-2)/2; int added = 0; if (c->argc % 2) { addReply(c,shared.syntaxerr); return; } /* Start parsing all the scores, we need to emit any syntax error * before executing additions to the sorted set, as the command should * either execute fully or nothing at all. */ scores = zmalloc(sizeof(double)*elements); for (j = 0; j < elements; j++) { if (getDoubleFromObjectOrReply(c,c->argv[2+j*2],&scores[j],NULL) != REDIS_OK) { zfree(scores); return; } } 。。。。 } 复制代码 复制代码 int getDoubleFromObjectOrReply(redisClient *c, robj *o, double *target, const char *msg) { double value; if (getDoubleFromObject(o, &value) != REDIS_OK) { if (msg != NULL) { addReplyError(c,(char*)msg); } else { addReplyError(c,"value is not a valid float"); } return REDIS_ERR; } *target = value; return REDIS_OK; } int getDoubleFromObject(robj *o, double *target) { double value; char *eptr; if (o == NULL) { value = 0; } else { redisAssertWithInfo(NULL,o,o->type == REDIS_STRING); if (o->encoding == REDIS_ENCODING_RAW) { errno = 0; value = strtod(o->ptr, &eptr); if (isspace(((char*)o->ptr)[0]) || eptr[0] != '\0' || errno == ERANGE || isnan(value)) return REDIS_ERR; } else if (o->encoding == REDIS_ENCODING_INT) { value = (long)o->ptr; } else { redisPanic("Unknown string encoding"); } } *target = value; return REDIS_OK; } 复制代码 利用strtod写个小程序 复制代码 #include
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值