9

Does Lua make use of 64-bit integers? How do I use it?

Nick Van Brunt
  • 15,244
  • 11
  • 66
  • 92
Aaron de Windt
  • 16,794
  • 13
  • 47
  • 62

3 Answers3

14

Compile it yourself. Lua uses double-precision floating point numbers by default. However, this can be changed in the source (luaconf.h, look for LUA_NUMBER).

Joey
  • 344,408
  • 85
  • 689
  • 683
  • 8
    To clarify, Lua has a single numerical data type. By default this is a `double`, but can be changed in the header files to another type, such as `int64_t`. – Yann Ramin Jun 23 '10 at 19:18
  • 2
    If you change the number type in `luaconf.h`, don't forget to change the related macros accordingly. – lhf Jun 23 '10 at 21:44
  • @lhf: It's documented right above the macro, though, so I thought it'd be pretty discoverable. – Joey Jun 23 '10 at 22:17
  • 3
    Note that this will have some sweeping side effects, since this is the only type numbers will have. For example, `math.sin` is not necessarily sensible with an integral type for LUA_NUMBER. There is a patch to the Lua sources, known as the LNUM patch, which can mitigate this by supporting an integral type alongside a floating point type. See http://stackoverflow.com/questions/945731/what-is-the-maximum-value-of-a-number-in-lua/947763#947763 – RBerteig Jun 24 '10 at 00:15
  • I am making an apps to use at the pge lua game engine on the psp. I was thinking to define the type of the variable, just as in VB.NET or C#. – Aaron de Windt Jun 24 '10 at 00:34
  • 2
    @Aaron: There is only a single numerical type and even with the LNUM patch RBerteig mentioned that doesn't change from the programmer's point of view – you just suddenly have 64-bit integers alongside with doubles and as far as I understood it choosing the correct type will be done automatically. You don't declare types in Lua as you do in VB or C# – those languages use a completely different typing discipline. – Joey Jun 24 '10 at 07:23
7
require "bit"

-- Lua unsigned 64bit emulated bitwises
-- Slow. But it works.

function i64(v)
 local o = {}; o.l = v; o.h = 0; return o;
end -- constructor +assign 32-bit value

function i64_ax(h,l)
 local o = {}; o.l = l; o.h = h; return o;
end -- +assign 64-bit v.as 2 regs

function i64u(x)
 return ( ( (bit.rshift(x,1) * 2) + bit.band(x,1) ) % (0xFFFFFFFF+1));
end -- keeps [1+0..0xFFFFFFFFF]

function i64_clone(x)
 local o = {}; o.l = x.l; o.h = x.h; return o;
end -- +assign regs

-- Type conversions

function i64_toInt(a)
  return (a.l + (a.h * (0xFFFFFFFF+1)));
end -- value=2^53 or even less, so better use a.l value

function i64_toString(a)
  local s1=string.format("%x",a.l);
  local s2=string.format("%x",a.h);
  local s3="0000000000000000";
  s3=string.sub(s3,1,16-string.len(s1))..s1;
  s3=string.sub(s3,1,8-string.len(s2))..s2..string.sub(s3,9);
  return "0x"..string.upper(s3);
end

-- Bitwise operators (the main functionality)

function i64_and(a,b)
 local o = {}; o.l = i64u( bit.band(a.l, b.l) ); o.h = i64u( bit.band(a.h, b.h) ); return o;
end

function i64_or(a,b)
 local o = {}; o.l = i64u( bit.bor(a.l, b.l) ); o.h = i64u( bit.bor(a.h, b.h) ); return o;
end

function i64_xor(a,b)
 local o = {}; o.l = i64u( bit.bxor(a.l, b.l) ); o.h = i64u( bit.bxor(a.h, b.h) ); return o;
end

function i64_not(a)
 local o = {}; o.l = i64u( bit.bnot(a.l) ); o.h = i64u( bit.bnot(a.h) ); return o;
end

function i64_neg(a)
 return i64_add( i64_not(a), i64(1) );
end  -- negative is inverted and incremented by +1

-- Simple Math-functions

-- just to add, not rounded for overflows
function i64_add(a,b)
 local o = {};
 o.l = a.l + b.l;
 local r = o.l - 0xFFFFFFFF;
 o.h = a.h + b.h;
 if( r>0 ) then
   o.h = o.h + 1;
   o.l = r-1;
 end
 return o;
end

-- verify a>=b before usage
function i64_sub(a,b)
  local o = {}
  o.l = a.l - b.l;
  o.h = a.h - b.h;
  if( o.l<0 ) then
    o.h = o.h - 1;
    o.l = o.l + 0xFFFFFFFF+1;
  end
  return o;
end

-- x n-times
function i64_by(a,n)
 local o = {};
 o.l = a.l;
 o.h = a.h;
 for i=2, n, 1 do
   o = i64_add(o,a);
 end
 return o;
end
-- no divisions   

-- Bit-shifting

function i64_lshift(a,n)
 local o = {};
 if(n==0) then
   o.l=a.l; o.h=a.h;
 else
   if(n<32) then
     o.l= i64u( bit.lshift( a.l, n) ); o.h=i64u( bit.lshift( a.h, n) )+ bit.rshift(a.l, (32-n));
   else
     o.l=0; o.h=i64u( bit.lshift( a.l, (n-32)));
   end
  end
  return o;
end

function i64_rshift(a,n)
 local o = {};
 if(n==0) then
   o.l=a.l; o.h=a.h;
 else
   if(n<32) then
     o.l= bit.rshift(a.l, n)+i64u( bit.lshift(a.h, (32-n))); o.h=bit.rshift(a.h, n);
   else
     o.l=bit.rshift(a.h, (n-32)); o.h=0;
   end
  end
  return o;
end

-- Comparisons

function i64_eq(a,b)
 return ((a.h == b.h) and (a.l == b.l));
end

function i64_ne(a,b)
 return ((a.h ~= b.h) or (a.l ~= b.l));
end

function i64_gt(a,b)
 return ((a.h > b.h) or ((a.h == b.h) and (a.l >  b.l)));
end

function i64_ge(a,b)
 return ((a.h > b.h) or ((a.h == b.h) and (a.l >= b.l)));
end

function i64_lt(a,b)
 return ((a.h < b.h) or ((a.h == b.h) and (a.l <  b.l)));
end

function i64_le(a,b)
 return ((a.h < b.h) or ((a.h == b.h) and (a.l <= b.l)));
end


-- samples
a = i64(1);               -- 1
b = i64_ax(0x1,0);        -- 4294967296 = 2^32
a = i64_lshift(a,32);     -- now i64_eq(a,b)==true
print( i64_toInt(b)+1 );  -- 4294967297

X = i64_ax(0x00FFF0FF, 0xFFF0FFFF);
Y = i64_ax(0x00000FF0, 0xFF0000FF);

-- swap algorithm
X = i64_xor(X,Y);
Y = i64_xor(X,Y);
X = i64_xor(X,Y);

print( "X="..i64_toString(X) ); -- 0x00000FF0FF0000FF
print( "Y="..i64_toString(Y) ); -- 0x00FFF0FFFFF0FFFF
  • 1
    Why don't you define a class with metatable fields to support the arithmeric operators ? And why no function for converting these numbers to decimal strings (you can also bind this function to the the '__string' metatable) ? Note: if Lua is compiled to support numbers with IEEE 64-bit doubles, it stores exactly all numbers with absolute value <= (2^53). – verdy_p Apr 19 '15 at 03:16
5

Lua 5.3 introduces the integer subtype, which uses 64-bit integer by default.

From Lua 5.3 reference manual

The type number uses two internal representations, one called integer and the other called float. Lua has explicit rules about when each representation is used, but it also converts between them automatically as needed (see §3.4.3). Therefore, the programmer may choose to mostly ignore the difference between integers and floats or to assume complete control over the representation of each number. Standard Lua uses 64-bit integers and double-precision (64-bit) floats, but you can also compile Lua so that it uses 32-bit integers and/or single-precision (32-bit) floats. The option with 32 bits for both integers and floats is particularly attractive for small machines and embedded systems. (See macro LUA_32BITS in file luaconf.h.)

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
  • Yes, this is much faster than emulations using arrays of 32-bit integers or strings for storing exact values. However Lua may be also easily ported to run in other host languages than C or C++ (e.g. in PHP, Java or Javascript), offering other native numeric datatypes, or numbers with higher precision (such as 80-bit long double in x86 architectures). With emulation, you can also support complex numbers or matrixes in Lua. – verdy_p Apr 19 '15 at 03:10