-
Notifications
You must be signed in to change notification settings - Fork 3.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
sjson.encode should use more digits in floating point numbers #3213
Comments
It turns out that the actual conversion is done by this line of code (from
which is doomed to failure. It turns out (from doing a quick google search) that this is a tough problem to get right -- when you want value -> string -> value to end up with the same value that you started with. In my case, I'd be happy if it was right to within a few bits of precision -- getting the last few bits always appears to be a problem. Actually, this may not be a problem -- we are only using floats (rather than doubles) which have terrible accuracy anyway, so it probably doesn't matter. |
I'm now more confused -- the docs seem to indicate that we are using
returns
|
@pjsg, it depends on whether you are using Lua51 or Lua53. Lua 51 uses a 12 byte Tvalue where all numerics are stored as double which allows precise representation of 53 bit integers. The latter uses an 8 byte TValue where Numeric values are either the subtype integer (32 bit) or single float (32 bit with 24 bit mantissa). It's basically a trade-off. The default Lua53 build has the RAM efficiency of old integer build but with the convenience of being able to use FP when needed. I have yet to come across a real world DAC or ADC that gives more than about 12 bits accuracy, so worrying about rounding errors after 12 d.p. seems a little excessive to me. 32-bit numerics are good enough for real-world IoT applications, IMO. I did design the Lua53 make so that for those that wanted to drop their effective RAM by a third, and slow runtime accordingly, then they could still configure the build to do 64bit float subtypes, but I haven't had a chance to try this out in anger. I did bounce this off the other committers in the Lua53 requirements discussions. |
I think that we need to update the documentation quite significantly to point out this change. We also need to review all uses of lua_pushnumber in our code to see if they should be changed to lua_pushinteger calls. In the lua51 world, it didn't matter because an integer had an exact float representation. This is no longer true. For example the current unix time is not usefully representable as a float ..... I'll file some tickets for the modules as I search through them. |
Philip, if you read the latest draft of the Lua 5.3 documentation you will see this covered in some depth, and it has been discussed in some depth as well. Everyone has their favourite point that they would like to see at the top of the documentation, but I can't put everyone's favourite as the first point. I have to assume that developers actually bother to read the documentation provided start to end. If you have specific changes that you want to suggest, that is what the review processes are for. |
Have you got a real world example of an IoT application that really requires 14 sig. fig. floating point calculation instead of 6? |
I would rephrase the question to "are there no iot apps that need integers
of more than 23 bits?"
Part of the problem is that some of the modules were cavalier about numbers
vs integers. This used to be fine as you could represent an integer (signed
or unsigned) exactly as a number. This is no longer true. This means that,
for example, a timestamp is not representable as a number. It is true that,
if we fixed all the firmware to use integers where appropriate, then with
careful Lua coding, you can probably get by with using floats.
…On Thu, Jul 16, 2020, 21:03 Terry Ellison ***@***.***> wrote:
Have you got a real world example of an IoT application that really
requires 14 sig. fig. floating point calculation instead of 6?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#3213 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AALQLTOQ4EA6VMNNRXRQGQ3R36PMBANCNFSM4O3KIR2A>
.
|
Part of the problem is that in some of the modules the wrong functions were used. For example, the For example, rtcmem.write32 coerces the values to numbers and then back to integers -- thus
will not return the expected value. This may, or may not, be serious. It is certainly surprising. |
Philip, none of this surprises me as I raised this as a risk when we had the debate six months ago. Going from a 64-bit Number type to a 32-bit (signed) integer + a 32-bit FP type increases the number of variable that can be stored in a fixed head size by perhaps roughly 20%. No free lunch, so there are some edge cases where we need to fix code. I did all of the Lua53 subsystem work, I did a lot of back porting to make the Lua51 and Lua53 C APIs sufficiently compatible that all the Modules compile clean. I also emphasised the there may be a few edge cases where we need to sort out number vs integer. I had hoped that at least one other committer would take on this task, or at least work with me on this. It sometimes gets pretty lonely and frustrating doing everything on your own. Just checking standard Lua on the PC, the conversion of a numeric string and numeric strings larger than We just need to define what the determinate rules are and do a review to enforce these. |
Philip, IMO |
@pjsg, I've just gone through the potential to number vs integer changes in the modules and in fact all bar The code which uses the call lua_pushlstring(data->L, get_state_buffer(data, state), state->pos_cur - state->pos_begin);
LUA_NUMBER r = lua_tonumber(data->L, -1);
lua_pop(data->L, 1);
lua_pushnumber(data->L, r); the last three lines could just be coded as: #if LUA_VERSION_NUM == 501
lua_pushlstring(data->L, get_state_buffer(data, state), state->pos_cur - state->pos_begin);
LUA_NUMBER r = lua_tonumber(data->L, -1);
lua_pop(data->L, 1);
lua_pushnumber(data->L, r);
#else /* LUA_VERSION_NUM == 503 */
if (lua_stringtonumber (L, get_state_buffer(data, state)) == 0)
luaL_error(L, "JSON parse error: invalid number type"); /* or push 0 to maintain existing behaviour */
#endif /* LUA_VERSION_NUM */ This will convert whole integers to int subtype. Note that the |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
This seems to be handled at least partially in #3222 |
Expected behavior
floating point numbers are represented in JSON as a value that is equivalent to the number
Actual behavior
Numbers like 1594863744.123456 appear as 1.594864e+09 -- which loses a lot of information.
Test code
NodeMCU startup banner
The text was updated successfully, but these errors were encountered: