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