I am writing a simple Lua script to calculate a median from a Sorted Set (http://redis.io/commands/#sorted_set) within Redis 2.8. The script is below
local cnt = redis.call("ZCARD", KEYS[1])
if cnt > 0 then
if cnt%2 > 0 then
local mid = math.floor(cnt/2)
return redis.call("ZRANGE", KEYS[1], mid, mid)
else
local mid = math.floor(cnt/2)
local vals = redis.call("ZRANGE", KEYS[1], mid-1, mid)
return (tonumber(vals[1]) + tonumber(vals[2]))/2.0
end
else
return nil
end
The problem is the script always returns an integer, when the result should be a float. The result is wrong.
$ redis-cli zrange floats 0 100
1) "1.1"
2) "2.1"
3) "3.1"
4) "3.4975"
5) "42.63"
6) "4.1"
$ redis-cli EVAL "$(cat median.lua)" 1 floats
(integer) 3
The correct result should be (3.1 + 3.4975)/2.0 == 3.298
We can convert a string to float in Python using float() function. It's a built-in function to convert an object to floating point number. Internally float() function calls specified object __float__() function.
We can convert String to float in java using Float. parseFloat() method.
Float isn't basic type of values in Lua, so function type() return only number. If i remember correctly, all numbers are floating point in Lua. Integers are only floating point numbers without the decimals.
You can convert strings to numbers using the function tonumber() . This takes a string argument and returns a number.
From the documentation for EVAL
:
Lua has a single numerical type, Lua numbers. There is no distinction between integers and floats. So we always convert Lua numbers into integer replies, removing the decimal part of the number if any. If you want to return a float from Lua you should return it as a string, exactly like Redis itself does (see for instance the ZSCORE command).
Therefore, you should update your script so you are returning the float as a string:
return tostring((tonumber(vals[1]) + tonumber(vals[2]))/2.0)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With