lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Hi everyone,
Lua-5.2 will have support for hexadecimal floats.

Please, find attached a patch against Lua-5.1.4-4  [1] that adds hex
floats to Lua-5.1.
You can use "%A" or "%a" format specifier to string.format to
serialize Lua number to its exact hexadecimal representation. You can
also read it back from the floating point hex representation.

sh$ lua
Lua 5.1.4  Copyright (C) 1994-2008 Lua.org, PUC-Rio
> =("%a"):format(1.0987654321e-20)
0x1.9f1a12718ed76p-67
> = 0x1.9f1a12718ed76p-67
1.0987654321e-20
> =tonumber("0x1.9f1a12718ed76p-67")
1.0987654321e-20
>

--Leo--

[1] Lua-5.1.4-4 is the official Lua-5.1.4 release plus the patches
found in  http://www.lua.org/ftp/patch-lua-5.1.4-4
From a787785fc03074d5dd49b0942cacea59b3d50a96 Mon Sep 17 00:00:00 2001
From: Leo Razoumov <LEOR@pionL2>
Date: Fri, 11 Nov 2011 17:45:56 -0500
Subject: [Lua-5.1.4 patch] support for hexadecimal floats

lua_Number (double) has no exact decimal representation because base_2 and base_10
are incompatible bases. As such, one cannot serialize lua_Number to decimal string 
and read it back without, in general, changing its value. To address the problem
C99 as well as many modern libc representations support exact hexadecimal 
representation of floats in printf/scanf ("%a", "%A"), strtod functions. 

This patch adds support for hexadecimal floats to Lua lexer and to string.format
function. Now Lua can serialize to strings and read back lua_Number(s) exactly.

sh$ lua
Lua 5.1.4  Copyright (C) 1994-2008 Lua.org, PUC-Rio
> =("%a"):format(1.0987654321e-20)
0x1.9f1a12718ed76p-67
> = 0x1.9f1a12718ed76p-67
1.0987654321e-20
> =tonumber("0x1.9f1a12718ed76p-67")
1.0987654321e-20
>


************************************************************************
This patch is against Lua-5.1.4-4 which is the official Lua-5.1.4 release
plus all the official patches contained in 
http://www.lua.org/ftp/patch-lua-5.1.4-4

To apply this patch issue
  sh$ cd /path/to/lua-5.1.4/distribution
  sh$ patch -p1 < hex-floats-lua-5.1.4-4.diff
************************************************************************

Signed-off-by: Leo Razoumov <LEOR@pionL2>
---
 src/llex.c    |   18 +++++++++++++-----
 src/lstrlib.c |    3 +++
 2 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/src/llex.c b/src/llex.c
index 88c6790..501a5d8 100644
--- a/src/llex.c
+++ b/src/llex.c
@@ -193,11 +193,19 @@ static void trydecpoint (LexState *ls, SemInfo *seminfo) {
 /* LUA_NUMBER */
 static void read_numeral (LexState *ls, SemInfo *seminfo) {
   lua_assert(isdigit(ls->current));
-  do {
-    save_and_next(ls);
-  } while (isdigit(ls->current) || ls->current == '.');
-  if (check_next(ls, "Ee"))  /* `E'? */
-    check_next(ls, "+-");  /* optional exponent sign */
+  if (check_next(ls, "0") && check_next(ls, "Xx")) {/* Hex int or float */
+      do {
+          save_and_next(ls);
+      } while (isxdigit(ls->current) || ls->current == '.');
+      if (check_next(ls, "Pp"))  /* `P'? binary exponent */
+          check_next(ls, "+-");  /* optional exponent sign */
+  } else { /* Decimal int or float number */
+      do {
+          save_and_next(ls);
+      } while (isdigit(ls->current) || ls->current == '.');
+      if (check_next(ls, "Ee"))  /* `E'? */
+          check_next(ls, "+-");  /* optional exponent sign */
+  }
   while (isalnum(ls->current) || ls->current == '_')
     save_and_next(ls);
   save(ls, '\0');
diff --git a/src/lstrlib.c b/src/lstrlib.c
index 7a03489..95f812c 100644
--- a/src/lstrlib.c
+++ b/src/lstrlib.c
@@ -788,6 +788,9 @@ static int str_format (lua_State *L) {
           break;
         }
         case 'e':  case 'E': case 'f':
+#ifdef LUA_NUMBER_DOUBLE
+        case 'a': case 'A':
+#endif
         case 'g': case 'G': {
           sprintf(buff, form, (double)luaL_checknumber(L, arg));
           break;
-- 
1.7.4.5.LR1