3

I'd like to convert a number to a string using only any Lua version, so that

  • there is no data loss (necessary!)

  • the string representation is as small as possible (8 bytes would be fine) (optional, not necessary)
  • no external libs are used (necessary!)

  • the conversion is as fast as possible (optional, not necessary)

I don't care about

  • human readability
  • avoiding special characters

I tried the built-in tonumber function, but it does not always give correct results:

> print((2+256^6)==(1+256^6))
false
> print(tostring(2+256^6)==tostring(1+256^6))
true
brianolive
  • 1,573
  • 2
  • 9
  • 19
KGM
  • 287
  • 2
  • 9
  • 1
    floating point numbers are lossy by definition - if you really need to avoid *any* data loss you can't use floats to begin with. – dimo414 Jul 07 '18 at 11:03
  • lua has one number data type - these numbers are doubles - i want to be able to serialize these in order to be able to serializing anything except userdata & threads ... – KGM Jul 07 '18 at 12:20
  • can someone post a complete solution? – KGM Jul 07 '18 at 12:28
  • SO is not a place where complete solution is given – Dimitry Jul 07 '18 at 14:54
  • where do you get that from? I saw many complete solutions to small problems like mine! I don't think serializing a number is big science. Furthermore, if there are only faulty answers, guys who embed them in their programs get serious problems! They try to serialize a nan and wonder why they get nil when they deserialize the data! – KGM Jul 07 '18 at 15:45
  • Your requirement - that you *never* lose precision - is not a small problem. [Revisit your requirements](https://meta.stackexchange.com/q/66377/147573) and you'll have an easier time getting an actionable answer. – dimo414 Jul 08 '18 at 03:07
  • any "double" (IEEE 754, "double precision") can be stored using 8 bytes. the question is how to do that using pure lua only. Any compressing format would be great. – KGM Jul 09 '18 at 13:36

3 Answers3

4

If you can use standard Lua libs, try these:

x=math.pi

s=string.pack("d",x)
y=string.unpack("d",s)
print(x==y)

s=string.format("%a",x)
y=tonumber(s)
print(x==y)

string.format("%a",x) is available in Lua 5.2+. string.pack is available in Lua 5.3+.

lhf
  • 70,581
  • 9
  • 108
  • 149
  • seems better than tostring! how deserialize? is there a string.format in any lua version? – KGM Jul 07 '18 at 11:28
  • Tried it out: yout can't deserialize (-)nans and (-)infs using tonumber, but seems fine for any other. – KGM Jul 07 '18 at 11:43
  • Also (out of http://lua-users.org/wiki/StringLibraryTutorial about string.format) "The options A, a may be available in Lua 5.2 and greater." (it should work with any lua version), string.pack not in my lua at all. – KGM Jul 07 '18 at 11:50
  • "string.format("%a",x) is available in Lua 5.2+. string.pack is available in Lua 5.3+." - does not solve the question. also support nans, infs and their negative versions. – KGM Jul 07 '18 at 12:34
2
   -- Encoding/decoding without data loss

   local NaN_serialized = {
      [string.format('%.17g',   1/0 )] =  '1/0',
      [string.format('%.17g',  -1/0 )] = '-1/0',
      [string.format('%.17g',   0/0 )] =  '0/0',
      [string.format('%.17g', -(0/0))] =  '-(0/0)'
   }
   -- How to encode:
   str_value = string.format('%.17g', num_value):gsub('^.*', NaN_serialized):gsub(',', '.')

   -- How_to_decode:
   num_value = loadstring("return "..str_value)()
Egor Skriptunoff
  • 906
  • 1
  • 8
  • 23
  • seems to work (at least with the lua i use currently) . pro : very very short solution, kontra : the string representation is pretty large. – KGM Jul 12 '18 at 12:55
1

This includes a number_to_str and a number_from_str function :

https://github.com/bakpakin/binser/blob/master/binser.lua

Apparantly, they are capable of more than Lua's builtin tonumber...

Luatic
  • 8,513
  • 2
  • 13
  • 34
  • print(number_from_str(number_to_str(-(0/0)),1) == -(0/0)) gives false. this does not save the difference between nan and -nan, also, this is quite a lot code. If you forked it and made a version that worked it would be fine. – KGM Jul 07 '18 at 11:20
  • if NaNs are not handled, you could easily add it yourself. – Luatic Jul 07 '18 at 11:24
  • yes, but i don't want to check pages of code for further errors, if you do and you find nothing your solution is fine. – KGM Jul 07 '18 at 11:45
  • i havent got time to do so – Luatic Jul 07 '18 at 11:47
  • As for your `(-0/0)==(-0/0)` test, there is no "minus nan" https://stackoverflow.com/a/37759548/4687565 – Dimitry Jul 07 '18 at 14:56
  • Of course there is! print(0/0) gives -nan, print(-(0/0)) gives nan. (Lua 5.2.4) – KGM Jul 07 '18 at 15:52
  • Furthermore, print(number_from_str(number_to_str(-(0/0)),1)) gives -nan, print(-(0/0)) gives nan! (test shown earlier is invalid) (Lua 5.2.4) Dimitry, are you the guy who made faulty binser? – KGM Jul 07 '18 at 16:00