aboutsummaryrefslogtreecommitdiff
path: root/lobject.c
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2024-08-02 15:09:30 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2024-08-02 15:09:30 -0300
commit1bf4b80f1ace8384eb9dd6f7f8b67256b3944a7a (patch)
tree5162b1f662c4dcb6127ba03866096f70d0c298ab /lobject.c
parent4c6afbcb01d1cae72d829af5301df5f592fa2079 (diff)
downloadlua-1bf4b80f1ace8384eb9dd6f7f8b67256b3944a7a.tar.gz
lua-1bf4b80f1ace8384eb9dd6f7f8b67256b3944a7a.tar.bz2
lua-1bf4b80f1ace8384eb9dd6f7f8b67256b3944a7a.zip
Floats formatted with "correct" precision
Conversion float->string ensures that, for any float f, tonumber(tostring(f)) == f, but still avoiding noise like 1.1 converting to "1.1000000000000001".
Diffstat (limited to 'lobject.c')
-rw-r--r--lobject.c52
1 files changed, 39 insertions, 13 deletions
diff --git a/lobject.c b/lobject.c
index 1c4ea1af..f7159547 100644
--- a/lobject.c
+++ b/lobject.c
@@ -10,6 +10,7 @@
10#include "lprefix.h" 10#include "lprefix.h"
11 11
12 12
13#include <float.h>
13#include <locale.h> 14#include <locale.h>
14#include <math.h> 15#include <math.h>
15#include <stdarg.h> 16#include <stdarg.h>
@@ -401,29 +402,54 @@ int luaO_utf8esc (char *buff, unsigned long x) {
401/* 402/*
402** Maximum length of the conversion of a number to a string. Must be 403** Maximum length of the conversion of a number to a string. Must be
403** enough to accommodate both LUA_INTEGER_FMT and LUA_NUMBER_FMT. 404** enough to accommodate both LUA_INTEGER_FMT and LUA_NUMBER_FMT.
404** (For a long long int, this is 19 digits plus a sign and a final '\0', 405** For a long long int, this is 19 digits plus a sign and a final '\0',
405** adding to 21. For a long double, it can go to a sign, 33 digits, 406** adding to 21. For a long double, it can go to a sign, the dot, an
406** the dot, an exponent letter, an exponent sign, 5 exponent digits, 407** exponent letter, an exponent sign, 4 exponent digits, the final
407** and a final '\0', adding to 43.) 408** '\0', plus the significant digits, which are approximately the *_DIG
409** attribute.
408*/ 410*/
409#define MAXNUMBER2STR 44 411#define MAXNUMBER2STR (20 + l_floatatt(DIG))
410 412
411 413
412/* 414/*
413** Convert a number object to a string, adding it to a buffer 415** Convert a float to a string, adding it to a buffer. First try with
416** a not too large number of digits, to avoid noise (for instance,
417** 1.1 going to "1.1000000000000001"). If that lose precision, so
418** that reading the result back gives a different number, then do the
419** conversion again with extra precision. Moreover, if the numeral looks
420** like an integer (without a decimal point or an exponent), add ".0" to
421** its end.
422*/
423static int tostringbuffFloat (lua_Number n, char *buff) {
424 /* first conversion */
425 int len = l_sprintf(buff, MAXNUMBER2STR, LUA_NUMBER_FMT,
426 (LUAI_UACNUMBER)n);
427 lua_Number check = lua_str2number(buff, NULL); /* read it back */
428 if (check != n) { /* not enough precision? */
429 /* convert again with more precision */
430 len = l_sprintf(buff, MAXNUMBER2STR, LUA_NUMBER_FMT_N,
431 (LUAI_UACNUMBER)n);
432 }
433 /* looks like an integer? */
434 if (buff[strspn(buff, "-0123456789")] == '\0') {
435 buff[len++] = lua_getlocaledecpoint();
436 buff[len++] = '0'; /* adds '.0' to result */
437 }
438 return len;
439}
440
441
442/*
443** Convert a number object to a string, adding it to a buffer.
414*/ 444*/
415static unsigned tostringbuff (TValue *obj, char *buff) { 445static unsigned tostringbuff (TValue *obj, char *buff) {
416 int len; 446 int len;
417 lua_assert(ttisnumber(obj)); 447 lua_assert(ttisnumber(obj));
418 if (ttisinteger(obj)) 448 if (ttisinteger(obj))
419 len = lua_integer2str(buff, MAXNUMBER2STR, ivalue(obj)); 449 len = lua_integer2str(buff, MAXNUMBER2STR, ivalue(obj));
420 else { 450 else
421 len = lua_number2str(buff, MAXNUMBER2STR, fltvalue(obj)); 451 len = tostringbuffFloat(fltvalue(obj), buff);
422 if (buff[strspn(buff, "-0123456789")] == '\0') { /* looks like an int? */ 452 lua_assert(len < MAXNUMBER2STR);
423 buff[len++] = lua_getlocaledecpoint();
424 buff[len++] = '0'; /* adds '.0' to result */
425 }
426 }
427 return cast_uint(len); 453 return cast_uint(len);
428} 454}
429 455