532 lines
12 KiB
Lua
532 lines
12 KiB
Lua
local BigNumOpt = {}
|
|
|
|
local MAX_CHAR = 26
|
|
local CHAR_NUM = 64
|
|
local DIGIT_UNIT = 1000
|
|
local DIGIT_ONE = 1000
|
|
local DIGIT_TWO = 1000000
|
|
local DIGIT_THREE = 1000000000
|
|
local DIGIT_FOUR = 1000000000000
|
|
-- local MAX_INTEGER = math.maxinteger
|
|
local MAX_INTEGER = 999999999999999
|
|
local MIN_INTEGER = 1000000
|
|
|
|
function BigNumOpt.cloneBigNum(bigBum)
|
|
return {value = bigBum.value, unit = bigBum.unit}
|
|
end
|
|
|
|
function BigNumOpt.getRemainder(unit)
|
|
return ((unit -1)%MAX_CHAR + 1)
|
|
end
|
|
|
|
function BigNumOpt.getEmptyBigNum()
|
|
local data = {}
|
|
data.value = math.tointeger(0)
|
|
data.unit = math.tointeger(0)
|
|
return data
|
|
end
|
|
|
|
function BigNumOpt.unitToNum(unit)
|
|
if unit == 1 then
|
|
return DIGIT_ONE
|
|
elseif unit == 2 then
|
|
return DIGIT_TWO
|
|
elseif unit == 3 then
|
|
return DIGIT_THREE
|
|
elseif unit == 4 then
|
|
return DIGIT_FOUR
|
|
else
|
|
return DIGIT_UNIT^unit
|
|
end
|
|
end
|
|
|
|
function BigNumOpt.numToTargetUnit(value, unit, targetUnit)
|
|
while true do
|
|
if unit == targetUnit or value == 0 then
|
|
break
|
|
end
|
|
if unit > targetUnit then
|
|
value = value * DIGIT_UNIT
|
|
unit = unit - 1
|
|
elseif unit < targetUnit then
|
|
if math.abs(value) < DIGIT_UNIT then
|
|
value = 0
|
|
else
|
|
value = value // DIGIT_UNIT
|
|
end
|
|
unit = unit + 1
|
|
end
|
|
end
|
|
return value, unit
|
|
end
|
|
|
|
function BigNumOpt.adjustDisplayBigNum(data)
|
|
if not BigNumOpt.checkDisplayBigNumData(data) then
|
|
return data
|
|
end
|
|
while true do
|
|
if data.unit >= 0 then
|
|
break
|
|
end
|
|
data.value = data.value / DIGIT_UNIT
|
|
data.unit = data.unit + 1
|
|
end
|
|
while true do
|
|
if data.unit <= 0 or data.value >= 1 then
|
|
break
|
|
end
|
|
data.value = data.value * DIGIT_UNIT
|
|
data.unit = data.unit - 1
|
|
end
|
|
while true do
|
|
if data.value < DIGIT_UNIT then
|
|
break
|
|
end
|
|
data.value = data.value / DIGIT_UNIT
|
|
data.unit = data.unit + 1
|
|
end
|
|
while true do
|
|
if data.value > -DIGIT_UNIT then
|
|
break
|
|
end
|
|
data.value = data.value / DIGIT_UNIT
|
|
data.unit = data.unit + 1
|
|
end
|
|
if data.value == 0 then
|
|
data.unit = 0
|
|
end
|
|
return data
|
|
end
|
|
|
|
function BigNumOpt.adjustRealBigNum(data)
|
|
if data.value > 0 then
|
|
while true do
|
|
if data.value <= MAX_INTEGER then
|
|
break
|
|
end
|
|
data.value = data.value // DIGIT_UNIT
|
|
data.unit = data.unit + 1
|
|
end
|
|
while true do
|
|
if data.value >= MIN_INTEGER then
|
|
break
|
|
end
|
|
data.value = data.value * DIGIT_UNIT
|
|
data.unit = data.unit - 1
|
|
end
|
|
elseif data.value < 0 then
|
|
while true do
|
|
if data.value >= -MAX_INTEGER then
|
|
break
|
|
end
|
|
data.value = data.value // DIGIT_UNIT
|
|
data.unit = data.unit + 1
|
|
end
|
|
while true do
|
|
if data.value <= -MIN_INTEGER then
|
|
break
|
|
end
|
|
data.value = data.value * DIGIT_UNIT
|
|
data.unit = data.unit - 1
|
|
end
|
|
end
|
|
if data.value == 0 then
|
|
data.unit = 0
|
|
end
|
|
return data
|
|
end
|
|
|
|
function BigNumOpt.getValidValue4Power(value)
|
|
local finalValue = 0
|
|
if value >= 100 then
|
|
finalValue = math.ceil(value)
|
|
elseif value >= 10 then
|
|
finalValue = math.ceil(value*10)/10
|
|
elseif value >= 0 then
|
|
finalValue = math.ceil(value*100)/100
|
|
elseif value >= -10 then
|
|
finalValue = math.floor(value*100)/100
|
|
elseif value >= -100 then
|
|
finalValue = math.floor(value*10)/10
|
|
else
|
|
finalValue = math.floor(value)
|
|
end
|
|
if finalValue == math.ceil(finalValue) then
|
|
return math.ceil(finalValue)
|
|
else
|
|
return finalValue
|
|
end
|
|
end
|
|
|
|
function BigNumOpt.getValidValue(value)
|
|
local finalValue = 0
|
|
if value >= 100 then
|
|
finalValue = math.floor(value)
|
|
elseif value >= 10 then
|
|
finalValue = math.floor(value*10)/10
|
|
elseif value >= 0 then
|
|
finalValue = math.floor(value*100)/100
|
|
elseif value >= -10 then
|
|
finalValue = math.ceil(value*100)/100
|
|
elseif value >= -100 then
|
|
finalValue = math.ceil(value*10)/10
|
|
else
|
|
finalValue = math.ceil(value)
|
|
end
|
|
if finalValue == math.floor(finalValue) then
|
|
return math.floor(finalValue)
|
|
else
|
|
return finalValue
|
|
end
|
|
end
|
|
|
|
function BigNumOpt.bigNum2Str4Power(bigNum)
|
|
local data = BigNumOpt.cloneBigNum(bigNum)
|
|
local tmp = BigNumOpt.adjustDisplayBigNum(data)
|
|
return BigNumOpt.getValidValue4Power(tmp.value) .. BigNumOpt.getBigNumUnit(tmp.unit)
|
|
end
|
|
|
|
-- 大数字转换
|
|
function BigNumOpt.bigNum2Str(bigNum)
|
|
local data = BigNumOpt.cloneBigNum(bigNum)
|
|
local tmp = BigNumOpt.adjustDisplayBigNum(data)
|
|
return BigNumOpt.getValidValue(tmp.value) .. BigNumOpt.getBigNumUnit(tmp.unit)
|
|
end
|
|
|
|
function BigNumOpt.bigNum2Num(bigNum)
|
|
--@TODO 2023-03-20 23:36:11
|
|
return math.floor(bigNum.value * (BigNumOpt.unitToNum(bigNum.unit)))
|
|
end
|
|
|
|
function BigNumOpt.num2BigNum(num)
|
|
local data = BigNumOpt.getEmptyBigNum()
|
|
data.value = num
|
|
BigNumOpt.adjustRealBigNum(data)
|
|
return data
|
|
end
|
|
|
|
function BigNumOpt.checkDisplayBigNumData(data)
|
|
if not data or not data.value or not data.unit then
|
|
return false
|
|
end
|
|
if not data.value then
|
|
return false
|
|
end
|
|
return true
|
|
end
|
|
|
|
function BigNumOpt.checkBigNumData(data)
|
|
if not data or not data.value or not data.unit then
|
|
return false
|
|
end
|
|
if math.type(data.value) ~= "integer" then
|
|
local value = math.floor(data.value)
|
|
data.value = math.tointeger(value)
|
|
end
|
|
if not data.value then
|
|
return false
|
|
end
|
|
return true
|
|
end
|
|
|
|
function BigNumOpt.bigNumAdd(data1, data2)
|
|
local data = BigNumOpt.getEmptyBigNum()
|
|
if not BigNumOpt.checkBigNumData(data1) or not BigNumOpt.checkBigNumData(data2) then
|
|
return data
|
|
end
|
|
local value1 = data1.value
|
|
local value2 = data2.value
|
|
local unit1 = data1.unit
|
|
local unit2 = data2.unit
|
|
|
|
if unit1 > unit2 then
|
|
-- data.value = value1*(BigNumOpt.unitToNum(unit1 - unit2)) + value2
|
|
-- data.unit = unit2
|
|
local value, unit = BigNumOpt.numToTargetUnit(value2, unit2, unit1)
|
|
data.value = value1 + value
|
|
data.unit = unit1
|
|
elseif unit1 < unit2 then
|
|
-- data.value = value1 + value2*(BigNumOpt.unitToNum(unit2 - unit1))
|
|
-- data.unit = unit1
|
|
local value, unit = BigNumOpt.numToTargetUnit(value1, unit1, unit2)
|
|
data.value = value + value2
|
|
data.unit = unit2
|
|
else
|
|
data.value = value1 + value2
|
|
data.unit = unit1
|
|
end
|
|
BigNumOpt.adjustRealBigNum(data)
|
|
return data
|
|
end
|
|
|
|
function BigNumOpt.bigNumSub(data1, data2)
|
|
local data = BigNumOpt.getEmptyBigNum()
|
|
if not BigNumOpt.checkBigNumData(data1) or not BigNumOpt.checkBigNumData(data2) then
|
|
return data
|
|
end
|
|
local value1 = data1.value
|
|
local value2 = data2.value
|
|
local unit1 = data1.unit
|
|
local unit2 = data2.unit
|
|
|
|
if unit1 > unit2 then
|
|
-- data.value = value1*(BigNumOpt.unitToNum(unit1 - unit2)) - value2
|
|
local value, unit = BigNumOpt.numToTargetUnit(value2, unit2, unit1)
|
|
data.value = value1 - value
|
|
data.unit = unit1
|
|
elseif unit1 < unit2 then
|
|
-- data.value = value1 - value2*(BigNumOpt.unitToNum(unit2 - unit1))
|
|
local value, unit = BigNumOpt.numToTargetUnit(value1, unit1, unit2)
|
|
data.value = value - value2
|
|
data.unit = unit2
|
|
else
|
|
data.value = value1 - value2
|
|
data.unit = unit1
|
|
end
|
|
BigNumOpt.adjustRealBigNum(data)
|
|
return data
|
|
end
|
|
|
|
function BigNumOpt.bigNumMultBigNum(data1, data2)
|
|
local data = BigNumOpt.getEmptyBigNum()
|
|
if not BigNumOpt.checkBigNumData(data1) or not BigNumOpt.checkBigNumData(data2) then
|
|
return data
|
|
end
|
|
local value1 = data1.value
|
|
local value2 = data2.value
|
|
local unit1 = data1.unit
|
|
local unit2 = data2.unit
|
|
|
|
if value1 > 0 then
|
|
while true do
|
|
if value1 <= MIN_INTEGER then
|
|
break
|
|
end
|
|
value1 = value1 // DIGIT_UNIT
|
|
unit1 = unit1 + 1
|
|
end
|
|
elseif value1 < 0 then
|
|
while true do
|
|
if value1 >= -MIN_INTEGER then
|
|
break
|
|
end
|
|
value1 = value1 // DIGIT_UNIT
|
|
unit1 = unit1 + 1
|
|
end
|
|
end
|
|
|
|
if value2 > 0 then
|
|
while true do
|
|
if value2 <= MIN_INTEGER then
|
|
break
|
|
end
|
|
value2 = value2 // DIGIT_UNIT
|
|
unit2 = unit2 + 1
|
|
end
|
|
elseif value2 < 0 then
|
|
while true do
|
|
if value2 >= -MIN_INTEGER then
|
|
break
|
|
end
|
|
value2 = value2 // DIGIT_UNIT
|
|
unit2 = unit2 + 1
|
|
end
|
|
end
|
|
|
|
data.value = value1*value2
|
|
data.unit = unit1 + unit2
|
|
|
|
BigNumOpt.adjustRealBigNum(data)
|
|
return data
|
|
end
|
|
|
|
function BigNumOpt.bigNumMultNum(bigNum, num)
|
|
local data = BigNumOpt.getEmptyBigNum()
|
|
if not BigNumOpt.checkBigNumData(bigNum) then
|
|
return data
|
|
end
|
|
local value = bigNum.value
|
|
data.unit = bigNum.unit
|
|
data.value = value*num
|
|
|
|
BigNumOpt.adjustRealBigNum(data)
|
|
return data
|
|
end
|
|
|
|
function BigNumOpt.bigNumDiv2Float(data1, data2)
|
|
if not BigNumOpt.checkBigNumData(data1) or not BigNumOpt.checkBigNumData(data2) then
|
|
return 0
|
|
end
|
|
|
|
local value1 = data1.value
|
|
local value2 = data2.value
|
|
local unit1 = data1.unit
|
|
local unit2 = data2.unit
|
|
|
|
if unit1 > unit2 then
|
|
return value1*(BigNumOpt.unitToNum(unit1 - unit2)) / value2
|
|
elseif unit1 < unit2 then
|
|
return value1 / (value2*(BigNumOpt.unitToNum(unit2 - unit1)))
|
|
else
|
|
return value1 / value2
|
|
end
|
|
end
|
|
|
|
-- 大数除以很小的数 用整除
|
|
function BigNumOpt.bigNumDivExactly(data1, num)
|
|
local data = BigNumOpt.getEmptyBigNum()
|
|
data.value = data1.value // num
|
|
data.unit = data1.unit
|
|
return data
|
|
end
|
|
|
|
function BigNumOpt.bigNumDiv(data1, data2)
|
|
local data = BigNumOpt.getEmptyBigNum()
|
|
if not BigNumOpt.checkBigNumData(data1) or not BigNumOpt.checkBigNumData(data2) then
|
|
return data
|
|
end
|
|
|
|
local value1 = data1.value
|
|
local value2 = data2.value
|
|
local unit1 = data1.unit
|
|
local unit2 = data2.unit
|
|
|
|
if value1 == 0 then
|
|
return data
|
|
end
|
|
local value = value1 / value2
|
|
if value >= MIN_INTEGER then
|
|
local value = math.floor(value)
|
|
data.value = math.tointeger(value)
|
|
data.unit = unit1 - unit2
|
|
else
|
|
local value = math.floor(value * DIGIT_TWO)
|
|
data.value = math.tointeger(value)
|
|
data.unit = unit1 - unit2 - 2
|
|
end
|
|
-- if data.unit < 0 then
|
|
-- local value = BigNumOpt.numToTargetUnit(data.value, data.unit, 0)
|
|
-- data.value = math.tointeger(math.floor(value))
|
|
-- data.unit = 0
|
|
-- end
|
|
-- if unit1 > unit2 then
|
|
-- data.value = value1*(BigNumOpt.unitToNum(unit1 - unit2)) // value2
|
|
-- data.unit = 0
|
|
-- elseif unit1 < unit2 then
|
|
-- data.value = value1 // (value2*(BigNumOpt.unitToNum(unit2 - unit1)))
|
|
-- data.unit = 0
|
|
-- else
|
|
-- data.value = value1 // value2
|
|
-- data.unit = 0
|
|
-- end
|
|
|
|
if EDITOR_MODE then
|
|
if value1 > 0 and value2 > 0 and data.value < 0 then
|
|
Logger.logFatal("the value is out of range")
|
|
end
|
|
end
|
|
|
|
BigNumOpt.adjustRealBigNum(data)
|
|
return data
|
|
end
|
|
|
|
function BigNumOpt.bigNumDivNum(data1, num)
|
|
local value = data1.value / num
|
|
if math.floor(value) == value then
|
|
local data = BigNumOpt.getEmptyBigNum()
|
|
data.value = data1.value // num
|
|
data.unit = data1.unit
|
|
BigNumOpt.adjustRealBigNum(data)
|
|
return data
|
|
end
|
|
local data2 = BigNumOpt.num2BigNum(num)
|
|
return BigNumOpt.bigNumDiv(data1, data2)
|
|
end
|
|
|
|
function BigNumOpt.bigNumCompare(data1, data2)
|
|
local data = BigNumOpt.getEmptyBigNum()
|
|
if not BigNumOpt.checkBigNumData(data1) or not BigNumOpt.checkBigNumData(data2) then
|
|
return
|
|
end
|
|
|
|
local value1 = data1.value
|
|
local value2 = data2.value
|
|
local unit1 = data1.unit
|
|
local unit2 = data2.unit
|
|
|
|
local data = BigNumOpt.bigNumSub(data1, data2)
|
|
if data.value > 0 then
|
|
return 1
|
|
elseif data.value < 0 then
|
|
return -1
|
|
else
|
|
return 0
|
|
end
|
|
end
|
|
|
|
function BigNumOpt.bigNumSqrt(data1)
|
|
if not BigNumOpt.checkBigNumData(data1) then
|
|
return data1
|
|
end
|
|
local data = BigNumOpt.getEmptyBigNum()
|
|
local value = data1.value
|
|
local unit = data1.unit
|
|
|
|
if value == 0 then
|
|
return data
|
|
end
|
|
if unit % 2 == 0 then
|
|
value = math.sqrt(value)
|
|
unit = unit / 2
|
|
else
|
|
value = math.sqrt(value*DIGIT_ONE)
|
|
unit = (unit - 1) / 2
|
|
end
|
|
if value >= MIN_INTEGER then
|
|
value = math.floor(value)
|
|
data.value = math.tointeger(value)
|
|
data.unit = unit
|
|
else
|
|
value = math.floor(value * DIGIT_TWO)
|
|
data.value = math.tointeger(value)
|
|
data.unit = unit - 2
|
|
end
|
|
return data
|
|
end
|
|
|
|
-- 单位转字符
|
|
function BigNumOpt.getBigNumUnit(unit)
|
|
if unit <= 0 then
|
|
return ""
|
|
end
|
|
local curDigit = 0
|
|
local unitStr = ""
|
|
while true do
|
|
local re = BigNumOpt.getRemainder(unit)
|
|
unitStr = string.char(re + CHAR_NUM) .. unitStr
|
|
if unit <= MAX_CHAR then
|
|
break
|
|
else
|
|
unit = (unit - re)/MAX_CHAR
|
|
end
|
|
end
|
|
return unitStr
|
|
end
|
|
|
|
--attr转str
|
|
-- function BigNumOpt.bigNumCfgAttr2FinalStr(cfgAttr)
|
|
-- local finalValueStr = BigNumOpt.bigNumCfgAttr2FinalValueStr(cfgAttr)
|
|
-- return GFunc.getPerStr(GConst.ATTR_TYPE[cfgAttr.type], finalValueStr)
|
|
-- end
|
|
|
|
function BigNumOpt.bigNumCfgAttr2FinalValueStr(cfgAttr)
|
|
local attrStr = GFunc.getPerStr(GConst.ATTR_TYPE[cfgAttr.type], BigNumOpt.bigNum2Str(GFunc.getFinalAttr(GConst.ATTR_TYPE[cfgAttr.type], cfgAttr.bignum)))
|
|
return attrStr
|
|
end
|
|
|
|
function BigNumOpt.bigNumCfgAttr2FinalValueStr2(type, attrValue)
|
|
local attrStr = GFunc.getPerStr(type, BigNumOpt.bigNum2Str(GFunc.getFinalAttr(type, attrValue)))
|
|
return attrStr
|
|
end
|
|
|
|
return BigNumOpt |