—思路
—用一个列表保存数字值
—符号: 用一个字段表示正负符号
—进制: 目前只考虑支持10进制, 不考虑2/8/16进制等
—精确度: 不考虑小数点, 向下取整截取
—压位最大值: 理论上操作系统(64\32位)与Lua版本可能影响最大值;
— 如果要计算最大值,只要使用循环一直把数字增加到溢出,溢出前的值就是最大值;
— 在新的版本上会有math.maxinteger字段表示最大值;
— 我们暂且认为10^8是最大的整数值吧;(因为太长会被用e显示, 不方便查看);也就是说列表值最大为7个9
---思路
---用一个列表保存数字值
---符号: 用一个字段表示正负符号
---进制: 目前只考虑支持10进制, 不考虑2/8/16进制等
---精确度: 不考虑小数点, 向下取整截取
---压位最大值: 理论上操作系统(64\32位)与Lua版本可能影响最大值;
--- 如果要计算最大值,只要使用循环一直把数字增加到溢出,溢出前的值就是最大值;
--- 在新的版本上会有math.maxinteger字段表示最大值;
--- 我们暂且认为10^8是最大的整数值吧;(因为太长会被用e显示, 不方便查看);也就是说列表值最大为7个9
module(..., package.seeall)
local math = math -- 引入为local后,下文的使用效率更高
SIGN_MINUS = "+" -- 正数
SIGN_PLUS = "-" -- 负数
SIGN_ZERO = "" -- 0
NUM_MAX = math.pow(10,8) - 1
NUM_MIN = -NUM_MAX
NUM_MAX_LEN = #tostring(NUM_MAX)
local function add_digits(d1, d2)
-- 两个列表相加
local len;
local up = 0
local v1, v2;
local digits_sum_temp;
local digits = {}
if #d1 > #d2 then
len = #d1
else
len = #d2
end
for i=1, len do
v1 = d1[i]
v2 = d2[i]
if v1 == nil then v1 = 0 end
if v2 == nil then v2 = 0 end
digits_sum_temp = v1 + v2 + up
if digits_sum_temp > NUM_MAX then
up = 1
digits_sum_temp = digits_sum_temp - NUM_MAX - 1
else
up = 0
end
digits[i] = digits_sum_temp
end
if up == 1 then
digits[#digits + 1] = 1
end
return digits
end
local function sub_digits(d1, d2)
-- 两个列表相减
-- 如果d1 - d2 大于等于0 会返回新的列表
-- 否则会返回false
local len
local v1, v2
local digits_sum_temp
local digits = {}
local flag = false -- 去掉0
if #d1 < #d2 then
return false
end
len = #d1
for i=1, len do
k = len - i + 1
v1 = d1[k]
v2 = d2[k]
if v1 == nil then v1 = 0 end
if v2 == nil then v2 = 0 end
digits_sum_temp = v1 - v2
if digits_sum_temp < 0 then
return false
end
if digits_sum_temp > 0 then
flag = true
end
if flag then
digits[k] = digits_sum_temp
end
end
return digits
end
local function is_digits_zero(d)
-- 列表值为0
return d and type(d) == "table" and #d == 1 and d[1] == 0
end
local function is_digits_lt(d1, d2)
-- 比较列表 小于
return sub_digits(d1, d2) == false
end
local function is_digits_eq(d1, d2)
-- 比较列表大小 =
local d = sub_digits(d2, d1)
return is_digits_zero(d)
end
local CBigInt = {isBigInt=true}
CBigInt.__tostring = function(a)
if #a._digits == 0 then
return "0"
end
local res
if a._sign == SIGN_PLUS then
res = tostring(a._sign)
else
res = ""
end
local str_format = string.format("%%.%sd", NUM_MAX_LEN) -- 补0
for i=1, #a._digits do
k = #a._digits - i + 1
v = a._digits[k]
if k ~= #a._digits then
v = string.format(str_format, tonumber(v))
else
v = tostring(v)
end
res = res..v
end
return res
end
CBigInt.__add = function(a, b)
a, b = CBigInt.getBigInt(a), CBigInt.getBigInt(b)
local sum = CBigInt:create(0);
if b._sign == SIGN_ZERO then
sum = a
elseif a._sign == SIGN_ZERO then
sum = b
elseif a._sign == SIGN_MINUS and b._sign == SIGN_MINUS then
-- sum = a + b
sum._sign = SIGN_MINUS
sum._digits = add_digits(a._digits, b._digits) -- 其实有浪费计算
elseif a._sign == SIGN_MINUS and b._sign == SIGN_PLUS then
-- sum = a - b
if is_digits_lt(a._digits, b._digits) then
sum._sign = SIGN_PLUS
sum._digits = sub_digits(b._digits, a._digits)
elseif is_digits_eq(a._digits, b._digits) then
sum._sign = SIGN_ZERO
sum._digits = {[1] = 0}
else
sum._sign = SIGN_MINUS
sum._digits = sub_digits(a._digits, b._digits)
end
elseif a._sign == SIGN_PLUS and b._sign == SIGN_MINUS then
-- sum = b - a
if is_digits_lt(b._digits, a._digits) then
sum._sign = SIGN_PLUS
sum._digits = sub_digits(a._digits, b._digits)
elseif is_digits_eq(a._digits, b._digits) then
sum._sign = SIGN_ZERO
sum._digits = {[1] = 0}
else
sum._sign = SIGN_MINUS
sum._digits = sub_digits(b._digits, a._digits)
end
else
-- sum = -(a + b)
sum._sign = SIGN_PLUS
sum._digits = add_digits(a._digits, b._digits)
end
return sum
end
CBigInt.__sub = function(a, b)
a, b = CBigInt.getBigInt(a), CBigInt.getBigInt(b)
local res = CBigInt:create(0)
if a._sign == SIGN_ZERO then
res = CBigInt.copy(CBigInt.reverse_sign(b))
elseif b._sign == SIGN_ZERO then
res = CBigInt.copy(a)
elseif a._sign == SIGN_MINUS and b._sign == SIGN_MINUS then
if is_digits_eq(a._digits, b._digits) then
elseif is_digits_lt(a._digits, b._digits) then
res._sign = SIGN_PLUS
res._digits = sub_digits(b._digits, a._digits)
else
res._sign = SIGN_MINUS
res._digits = sub_digits(a._digits, b._digits)
end
elseif a._sign == SIGN_MINUS and b._sign == SIGN_PLUS then
res._sign = SIGN_MINUS
res._digits = add_digits(a._digits, b._digits)
elseif a._sign == SIGN_PLUS and b._sign == SIGN_MINUS then
res._sign = SIGN_PLUS
res._digits = add_digits(a._digits, b._digits)
else
if is_digits_eq(a._digits, b._digits) then
elseif is_digits_lt(a._digits, b._digits) then
res._sign = SIGN_MINUS
res._digits = sub_digits(b._digits, a._digits)
else
res._sign = SIGN_PLUS
res._digits = sub_digits(a._digits, b._digits)
end
end
return res
end
--CBigInt.__mul = function(a, b)
-- return a * b
--end
--CBigInt.__div = function(a, b)
-- return a / b
--end
--CBigInt.__len = function(a)
-- local s = CBigInt.__tostring(a)
-- return #s
--end
CBigInt.__eq = function(a, b)
a, b = CBigInt.getBigInt(a), CBigInt.getBigInt(b)
return a._sign == b._sign and is_digits_eq(a._digits, b._digits)
end
CBigInt.__lt = function(a, b)
-- 小于
a, b = CBigInt.getBigInt(a), CBigInt.getBigInt(b)
if a._sign == SIGN_MINUS then
if b._sign == SIGN_MINUS then
return is_digits_lt(a._digits, b._digits)
elseif b._sign == SIGN_PLUS then
return false
else
return false
end
elseif a._sign == SIGN_PLUS then
if b._sign == SIGN_MINUS then
return true
elseif b._sign == SIGN_PLUS then
return is_digits_lt(b._digits, a._digits)
else
return true
end
else
if b._sign == SIGN_MINUS then
return true
elseif b._sign == SIGN_PLUS then
return false
else
return false
end
end
end
CBigInt.__le = function(a, b)
-- 小于等于
return CBigInt.__lt(a, b) or CBigInt.__eq(a, b)
end
function CBigInt:_new(o)
o = o or {}
o._sign = SIGN_ZERO
o._digits = {[1] = 0}
self.__index = self
setmetatable(o, self)
return o
end
function CBigInt:_set(n)
if n == nil then
print("请输入有意义数字")
return
end
if type(n) == "number" then
return self:_set_number(n)
elseif type(n) == "string" then
return self:_set_string(n)
else
print(string.format("暂时不支持%s类型参数%s", type(n), tostring(n)))
end
end
function CBigInt:_set_number(n)
n = math.floor(n)
if n >= NUM_MIN and n <= NUM_MAX then
if n == 0 then
self._sign = SIGN_ZERO
elseif n < 0 then
n = -n
self._sign = SIGN_PLUS
else
self._sign = SIGN_MINUS
end
self._digits = {[1] = n}
return true
else
return self:_set_string(n)
end
end
function CBigInt:_set_string(n)
n = tostring(n)
n = n:gsub(" ", "")
local tmp = n:gsub("-?+?%.?", "")
if string.match(tmp, "%D") then
print(string.format("请检查输入的值不合法, 不支持字母:%s", n))
return
end
n = n:gsub("%.%d*", "")
if n == "" then
print(string.format("请检查输入的值不合法, 没有正值:%s", n))
return
end
if n:sub(1, 1) == "-" then
self._sign = SIGN_PLUS
n = n:sub(2)
elseif n:sub(1, 1) == "+" then
self._sign = SIGN_MINUS
n = n:sub(2)
else
self._sign = SIGN_MINUS
end
n = n:gsub("^0*", "")
if n == "" then
n = "0"
end
if n == "0" then
self._digits[1] = 0
self._sign = SIGN_ZERO
return true
end
local str;
local int;
self._digits = {}
for index=1, #n, NUM_MAX_LEN do
str = n:sub(-index-NUM_MAX_LEN+1, -index)
int = tonumber(str)
self._digits[#self._digits+1] = int
end
return true
end
function CBigInt.copy(a)
local b = CBigInt:create(0)
b._sign = a._sign
b._digits = {}
for i=1, #a._digits do
b._digits[i] = a._digits[i]
end
return b
end
function CBigInt.reverse_sign(a)
-- 正负符号反转
a = CBigInt.copy(a)
if a._sign == SIGN_MINUS then
a._sign = SIGN_PLUS
elseif a._sign == SIGN_PLUS then
a._sign = SIGN_MINUS
end
return a
end
function CBigInt.isBigInt(n)
return type(n) == "table" and n.isBigInt
end
function CBigInt.getBigInt(n)
if CBigInt.isBigInt(n) then
return CBigInt.copy(n)
else
return CBigInt:create(n)
end
end
function CBigInt:create(n)
local o = self:_new()
o:_set(n)
return o
end
--local a = "1"
--local b = ""
--for i=1, 10000 do
-- a = a.."1"
-- b = b.."2"
--end
--
--a = CBigInt:create(a)
--b = CBigInt:create(b)
--print(a + b)