/* ** $Id: lnum.c,v ... $ ** Internal number model ** See Copyright Notice in lua.h */ #include #include #include #include #include #include #define lnum_c #define LUA_CORE #include "lua.h" #include "llex.h" #include "lnum.h" /* ** lua_real2str converts a (non-complex) number to a string. ** lua_str2real converts a string to a (non-complex) number. */ #define lua_real2str(s,n) sprintf((s), LUA_NUMBER_FMT, (n)) /* * Note: Only 'strtod()' is part of ANSI C; others are C99 and * may need '--std=c99' compiler setting (at least on Ubuntu 7.10). * * Visual C++ 2008 Express does not have 'strtof()', nor 'strtold()'. * References to '_strtold()' exist but don't compile. It seems best * to leave Windows users with DOUBLE only (or compile with MinGW). * * In practise, using '(long double)strtod' is a risky thing, since * it will cause accuracy loss in reading in numbers, and such losses * will pile up in later processing. Get a real 'strtold()' or don't * use that mode at all. */ #ifdef LNUM_DOUBLE # define lua_str2real strtod #elif defined(LNUM_FLOAT) # define lua_str2real strtof #elif defined(LNUM_LDOUBLE) # define lua_str2real strtold #endif #define lua_integer2str(s,v) sprintf((s), LUA_INTEGER_FMT, (v)) /* 's' is expected to be LUAI_MAXNUMBER2STR long (enough for any number) */ void luaO_num2buf( char *s, const TValue *o ) { lua_Number n; lua_assert( ttisnumber(o) ); /* Reason to handle integers differently is not only speed, but accuracy as * well. We want to make any integer tostring() without roundings, at all. */ if (ttisint(o)) { lua_integer2str( s, ivalue(o) ); return; } n= nvalue_fast(o); lua_real2str(s, n); #ifdef LNUM_COMPLEX lua_Number n2= nvalue_img_fast(o); if (n2!=0) { /* Postfix with +-Ni */ int re0= (n == 0); char *s2= re0 ? s : strchr(s,'\0'); if ((!re0) && (n2>0)) *s2++= '+'; lua_real2str( s2, n2 ); strcat(s2,"i"); } #endif } /* * If a LUA_TNUMBER has integer value, give it. */ int /*bool*/ tt_integer_valued( const TValue *o, lua_Integer *ref ) { lua_Number d; lua_Integer i; lua_assert( ttype(o)==LUA_TNUMBER ); lua_assert( ref ); #ifdef LNUM_COMPLEX if (nvalue_img_fast(o)!=0) return 0; #endif d= nvalue_fast(o); lua_number2integer(i, d); if (cast_num(i) == d) { *ref= i; return 1; } return 0; } /* * Lua 5.1.3 (using 'strtod()') allows 0x+hex but not 0+octal. This is good, * and we should NOT use 'autobase' 0 with 'strtoul[l]()' for this reason. * * Lua 5.1.3 allows '0x...' numbers to overflow and lose precision; this is not * good. On Visual C++ 2008, 'strtod()' does not even take them in. Better to * require hex values to fit 'lua_Integer' or give an error that they don't? * * Full hex range (0 .. 0xff..ff) is stored as integers, not to lose any bits. * Numerical value of 0xff..ff will be -1, if used in calculations. * * Returns: TK_INT for a valid integer, '*endptr_ref' updated * TK_NUMBER for seemingly numeric, to be parsed as floating point * 0 for bad characters, not a number (or '0x' out of range) */ static int luaO_str2i (const char *s, lua_Integer *res, char **endptr_ref) { char *endptr; /* 'v' gets ULONG_MAX on possible overflow (which is > LUA_INTEGER_MAX); * we don't have to check 'errno' here. */ unsigned LUA_INTEGER v= lua_str2ul(s, &endptr, 10); if (endptr == s) return 0; /* nothing numeric */ if (v==0 && *endptr=='x') { errno= 0; /* needs to be set, 'strtoul[l]' does not clear it */ v= lua_str2ul(endptr+1, &endptr, 16); /* retry as hex, unsigned range */ if (errno==ERANGE) { /* clamped to 0xff..ff */ #if (defined(LNUM_INT32) && !defined(LNUM_FLOAT)) || defined(LNUM_LDOUBLE) return TK_NUMBER; /* Allow to be read as floating point (has more integer range) */ #else return 0; /* Reject the number */ #endif } else if (v > LUA_INTEGER_MAX) { return TK_NUMBER; } } else if ((v > LUA_INTEGER_MAX) || (*endptr && (!isspace(*endptr)))) { return TK_NUMBER; /* not in signed range, or has '.', 'e' etc. trailing */ } *res= (lua_Integer)v; *endptr_ref= endptr; return TK_INT; } /* 0 / TK_NUMBER / TK_INT (/ TK_NUMBER2) */ int luaO_str2d (const char *s, lua_Number *res_n, lua_Integer *res_i) { char *endptr; int ret= TK_NUMBER; /* Check integers first, if caller is allowing. * If 'res2'==NULL, they're only looking for floating point. */ if (res_i) { ret= luaO_str2i(s,res_i,&endptr); if (ret==0) return 0; } if (ret==TK_NUMBER) { lua_assert(res_n); /* Note: Visual C++ 2008 Express 'strtod()' does not read in "0x..." * numbers; it will read '0' and spit 'x' as endptr. * This means hex constants not fitting in 'lua_Integer' won't * be read in at all. What to do? */ *res_n = lua_str2real(s, &endptr); if (endptr == s) return 0; /* conversion failed */ /* Visual C++ 2008 'strtod()' does not allow "0x..." input. */ #if defined(_MSC_VER) && !defined(LNUM_FLOAT) && !defined(LNUM_INT64) if (*res_n==0 && *endptr=='x') { /* Hex constant too big for 'lua_Integer' but that could fit in 'lua_Number' * integer bits */ unsigned __int64 v= _strtoui64( s, &endptr, 16 ); /* We just let > 64 bit values be clamped to _UI64_MAX (MSDN does not say 'errno'==ERANGE would be set) */ *res_n= cast_num(v); if (*res_n != v) return 0; /* Would have lost accuracy */ } #endif #ifdef LNUM_COMPLEX if (*endptr == 'i') { endptr++; ret= TK_NUMBER2; } #endif } if (*endptr) { while (isspace(cast(unsigned char, *endptr))) endptr++; if (*endptr) return 0; /* invalid trail */ } return ret; } /* Functions for finding out, when integer operations remain in range * (and doing them). */ int try_addint( lua_Integer *r, lua_Integer ib, lua_Integer ic ) { lua_Integer v= ib+ic; /* may overflow */ if (ib>0 && ic>0) { if (v < 0) return 0; /*overflow, use floats*/ } else if (ib<0 && ic<0) { if (v >= 0) return 0; } *r= v; return 1; } int try_subint( lua_Integer *r, lua_Integer ib, lua_Integer ic ) { lua_Integer v= ib-ic; /* may overflow */ if (ib>=0 && ic<0) { if (v < 0) return 0; /*overflow, use floats*/ } else if (ib<0 && ic>0) { if (v >= 0) return 0; } *r= v; return 1; } int try_mulint( lua_Integer *r, lua_Integer ib, lua_Integer ic ) { if (ib!=LUA_INTEGER_MIN && ic!=LUA_INTEGER_MIN) { lua_Integer b= luai_abs(ib), c= luai_abs(ic); if ( (ib==0) || (LUA_INTEGER_MAX/b >= c) ) { *r= ib*ic; /* no overflow */ return 1; } } else if (ib==0 || ic==0) { *r= 0; return 1; } /* Result can be LUA_INTEGER_MIN; if it is, calculating it using floating * point will not cause accuracy loss. */ if ( luai_nummul( cast_num(ib), cast_num(ic) ) == LUA_INTEGER_MIN ) { *r= LUA_INTEGER_MIN; return 1; } return 0; } int try_divint( lua_Integer *r, lua_Integer ib, lua_Integer ic ) { /* N/0: leave to float side, to give an error */ if (ic==0) return 0; /* N/LUA_INTEGER_MIN: always non-integer results, or 0 or +1 */ if (ic==LUA_INTEGER_MIN) { if (ib==LUA_INTEGER_MIN) { *r=1; return 1; } if (ib==0) { *r=0; return 1; } /* LUA_INTEGER_MIN (-2^31|63)/N: calculate using float side (either the division * causes non-integer results, or there is no accuracy loss in int->fp->int * conversions (N=2,4,8,..,256 and N=2^30,2^29,..2^23). */ } else if (ib==LUA_INTEGER_MIN) { lua_Number d= luai_numdiv( cast_num(LUA_INTEGER_MIN), cast_num(ic) ); lua_Integer i; lua_number2integer(i,d); if (cast_num(i)==d) { *r= i; return 1; } } else { /* Note: We _can_ use ANSI C mod here, even on negative values, since * we only test for == 0 (the sign would be implementation dependent). */ if (ib%ic == 0) { *r= ib/ic; return 1; } } return 0; } int try_modint( lua_Integer *r, lua_Integer ib, lua_Integer ic ) { if (ic!=0) { /* ANSI C can be trusted when b%c==0, or when values are non-negative. * b - (floor(b/c) * c) * --> * + +: b - (b/c) * c (b % c can be used) * - -: b - (b/c) * c (b % c could work, but not defined by ANSI C) * 0 -: b - (b/c) * c (=0, b % c could work, but not defined by ANSI C) * - +: b - (b/c-1) * c (when b!=-c) * + -: b - (b/c-1) * c (when b!=-c) * * o MIN%MIN ends up 0, via overflow in calcs but that does not matter. * o MIN%MAX ends up MAX-1 (and other such numbers), also after overflow, * but that does not matter, results do. */ lua_Integer v= ib % ic; if ( v!=0 && (ib<0 || ic<0) ) { v= ib - ((ib/ic) - ((ib<=0 && ic<0) ? 0:1)) * ic; } /* Result should always have same sign as 2nd argument. (PIL2) */ lua_assert( (v<0) ? (ic<0) : (v>0) ? (ic>0) : 1 ); *r= v; return 1; } return 0; /* let float side return NaN */ } int try_powint( lua_Integer *r, lua_Integer ib, lua_Integer ic ) { /* In FLOAT/INT32 or FLOAT|DOUBLE/INT64 modes, calculating integer powers * via FP realm may lose accuracy (i.e. 7^11 = 1977326743, which fits int32 * but not 23-bit float mantissa). * * The current solution is dumb, but it works and uses little code. Use of * integer powers is not anticipated to be very frequent (apart from 2^x, * which is separately optimized). */ if (ib==0) *r=0; else if (ic<0) return 0; /* FP realm */ else if (ib==2 && ic < (int)sizeof(lua_Integer)*8-1) *r= ((lua_Integer)1)< LUA_INTEGER_MAX ) { errno= ERANGE; v= ULONG_MAX; } return (unsigned LUA_INTEGER)v; } #endif