Module:BigNumber/utils

From wiki
Jump to navigation Jump to search

local main_module = "Module:BigNumber" local utils = {} local cmath = {} local bignum = {} local lib_calc = {}

--大數帶餘長除法 / 可作為進制轉換用的帶餘長除法 function utils.modulo_div(n, _original_base, destination_base, fractional_flag) local original_base = tonumber(_original_base) local non_number_base = not original_base --確認是否為非數字進制 if non_number_base then original_base = 1 end local carry = 0 local result = {0} --儲存商的陣列 for i =fractional_flag and #n or 1,fractional_flag and 1 or #n, fractional_flag and -1 or 1 do if non_number_base then original_base = utils.getBaseValue(_original_base, fractional_flag and (-i) or (#n - i)) if utils.isInf(original_base) then original_base = 10 end --若混合底數出現無限大作為十進制計算 end local d = n[i] if fractional_flag then --進制轉換時,小數點以後用乘的 d = d * math.abs(destination_base) + carry carry = math.floor(d / original_base) d = utils.mod(d, original_base) if destination_base < 0 then d = -d end else --對每個位數進行帶餘長除法 d = d + original_base * carry --上一位的餘數,取下一位 carry = utils.mod(d, destination_base) --新的餘數 d = math.floor(d / destination_base) --商 end result[i] = math.floor(d) --紀錄商 end if fractional_flag and destination_base < 0 then carry = -carry end return result, carry --回傳商, 餘數 end

function utils._convertBase(n, _original_base, _destination_base, fractional_flag, total_digit) local digits = {} if utils.isInf(_original_base) then error(string.format("底數不能為 '%s'", tostring(_original_base)),2) end if fractional_flag and utils.isInf(_destination_base) then --無限大進制的小數位數位置值為 1/無限大 是零,無法表示小數 return {} end local original_base = utils.getBaseValue(_original_base, 0) local destination_base = utils.getBaseValue(_destination_base, 0) local dn, digit = n local max_digit = total_digit or math.max(#n+1, 20) --未指定時不超過20位 local i = 0 local src_max_digit = #dn

--進位轉換為不斷帶餘除法直到商為0 while not utils.is_zero(dn) do destination_base = utils.getBaseValue(_destination_base, fractional_flag and (-i - 1) or i) --以帶餘長除法計算各個位數 (回傳值 => 商, 位數) dn, digit = utils.modulo_div(dn, _original_base, destination_base, fractional_flag) if digit < 0 then --負底數進位會遇到餘數小於0的情況 digit = digit + math.abs(destination_base) --加成正的 if fractional_flag then else --商+1 (因為等於多減一次除數) dn[#dn] = dn[#dn] + 1 end end --計算小數時,位數加在末尾 if fractional_flag then if utils.isNaN(digit) then break end digits[#digits + 1] = digit if i >= max_digit then break end --計算整數時,位數加在開頭 else table.insert(digits, 1, digit) end i = i + 1 end return digits end

function utils.is_zero(n) for _,d in ipairs(n) do if d ~= 0 then return false end end return true end

function utils.myfloor(n) if math.abs(math.ceil(n)-n)<1e-12 then return math.ceil(n) end return math.floor(n) end

function utils.myceil(n) if math.abs(math.floor(n)-n)<1e-12 then return math.floor(n) end return math.ceil(n) end

function utils.round(n) return utils.myfloor(n + 0.5) end

function utils.mod(n, m) if utils.isInf(m) then return n end return n % m end

function utils.loop_mod(n, m) if utils.isInf(m) then return n end local result = n % m return (result == 0) and m or result end

function utils.tonumber(n) local check = tostring(n) check = mw.ustring.gsub(check, '∞', 'inf') return tonumber(check) end

function utils.tostring(n) local result = tostring(n) result = mw.ustring.gsub(result, '^%s*([+-]?)inf%s*$', '%1∞') result = mw.ustring.gsub(result, '%-', '−') return result end

function utils.isInt(n) return math.abs(utils.myfloor(n)-n)<1e-12 end

function utils.isInf(num) local num_str = tostring(num):lower() return num_str=='inf' or num_str=='-inf' or num_str=='−inf' or num_str=='+inf' end

function utils.isNaN(num) local num_str = tostring(num):lower() return num_str=='nan' or num_str=='-nan' or num_str=='−nan' or num_str=='+nan' end

function utils.cintpow(num, power) if type(cmath.constructor) ~= type(tostring) then cmath = require("Module:Complex Number").cmath.init()end power = utils.round(power) local this = cmath[0] + cmath.constructor(num) if power < 0 then --負的次方為倒數自乘 this = cmath.inverse(this) power = -power end if power == 0 then return cmath[0] + 1 end if power == 1 then return cmath[0] + this end if power == 2 then return this * this end local loge = math.log(power) local log2 = loge / math.log(2) if utils.isInt(log2) then --次方為2的冪 直接連續自乘,以減少乘法運算的次數 local result = this for i=1,log2 do result = result * result end return result end local times_data = {} local times_times = {} local two_time = utils.round(math.pow(2, math.floor(log2))) --其餘情況轉換成2的冪的組合,以減少乘法運算的次數 local lose_time = power - two_time local to_times = cmath[0] + this local zero_flag = 0 repeat --重複分成2的冪的組合 for i=1,log2 do to_times = to_times * to_times end times_data[#times_data+1] = to_times --紀錄本次自乘次數的結果 times_times[#times_times+1] = two_time log2 = math.log(lose_time) / math.log(2) --計算剩餘數字的2的冪的組合 two_time = math.pow(2, math.floor(log2)) lose_time = lose_time - two_time --計算扣除本次的2的冪的次數後剩下多少次要乘 to_times = cmath[0] + this if lose_time <= 0 then zero_flag = zero_flag + 1 end --剩餘次數為0為迴圈結束條件 until zero_flag > 1 local result = cmath[1] for i=1,#times_data do result = result * times_data[i]end --將所有自乘次數的結果相乘 return result end

function utils._swap(x,i,y,j) local t = x[i]; x[i] = y[j]; y[j] = t end

function utils.fibonacci_coding(int_digits, original_base, _destination_base, fractional_flag, total_digit, fib_code) local sqrt5 = math.sqrt(5) local phi = (sqrt5 + 1) * 0.5 local logphi = math.log(phi) local function fibonacciId(x)return utils.myceil(math.log(x*sqrt5-0.5)/logphi)end local function fibonacci(an)return math.floor(math.pow(phi, an) / sqrt5 + 0.5)end if fractional_flag then if fib_code then return {} end local number = utils.toDecimal({0}, int_digits, original_base) if number == 0 then return {} end local max_digs = total_digit or math.max(#int_digits + 1,20) local result = {} for i=1,max_digs do local place_value = 1 / fibonacci(i+2) if place_value > number then result[#result + 1] = 0 else result[#result + 1] = 1 number = number - place_value end if number == 0 then break end end return result end local n = utils.myfloor(utils.toDecimal(int_digits, {}, original_base)) if math.abs(tonumber(table.concat(int_digits,))-1)<1e-14 then return fib_code and {1,1} or {1,0} end

local k = utils.myceil(math.log(n*sqrt5-0.5)/logphi) local vaild_fib = {} local max_id = 0 local x0 = n while x0 > 0 do local id = fibonacciId(x0) local digval = fibonacci(id) if digval > x0 then id = id - 1 digval = fibonacci(id) end x0 = x0 - digval if id > max_id then max_id = id end vaild_fib[id] = 1 end local result = {} for i=max_id,(fib_code and 2 or 1),-1 do result[#result + 1] = vaild_fib[i] or 0 end if fib_code then local the_code = {1} for i=1,#result do table.insert(the_code, 1, result[i]) end return the_code end return result end

function utils.real_negabase(int_digits, fractional_digits, original_base, destination_base, _sign) local num = utils.toDecimal(int_digits, fractional_digits, original_base) local sign = _sign if _sign < 0 then sign = sign * -1 num = -num end local b = destination_base local sb = math.abs(b) local mb, pb = -sb / (sb + 1), 1 / (sb + 1) local lb, rb = mb, pb if lb > rb then lb, rb = pb, mb end local p_chack = math.log((num/lb > 0) and num/lb or num/rb)/math.log(sb) local fp, cp = math.floor(p_chack), math.ceil(p_chack) local lp, rp = fp, cp if lp > rp then lp, rp = cp, fp end local p_list = {lp-1, lp, rp, rp+1} local p = lp local min_x = math.huge for i=1,#p_list do local p0 = num / math.pow(b, p_list[i]) if p0 >= lb and p0 <= rb then if p0 < min_x then min_x = p0 p = p_list[i] end end end local Tb = function(x) return b*x - math.floor(b*x-lb) end local Tbj = min_x if p<0 then Tbj = num end local k = p local int_result, fractional_result = {}, {} for i=k-1,0,-1 do local digit = math.floor(b * Tbj - lb) Tbj = Tb(Tbj) int_result[#int_result + 1] = digit end if #int_result == 0 then int_result[1] = 0 end if math.abs(Tbj) > 0 then for i=1,20 do local digit = math.floor(b * Tbj - lb) Tbj = Tb(Tbj) fractional_result[#fractional_result + 1] = digit if math.abs(Tbj) <= 0 then break end end end return int_result, fractional_result, sign end

function utils.non_integer_base(int_digits, fractional_digits, original_base, destination_base, _sign) local n = utils.toDecimal(int_digits, fractional_digits, original_base) local sign = _sign if n < 0 then sign = sign * -1 n = -n end local k = utils.myfloor(math.log(n)/math.log(destination_base)) + 1 local int_result, fractional_result = {}, {} for i=k-1,0,-1 do local digit = utils.myfloor((n / utils.getPlaceValue(destination_base, i)) % destination_base) n = n - digit * utils.getPlaceValue(destination_base, i) int_result[#int_result + 1] = digit end if n > 0 then for i=1,20 do local digit = utils.myfloor((n / utils.getPlaceValue(destination_base, -i)) % destination_base) n = n - digit * utils.getPlaceValue(destination_base, -i) fractional_result[#fractional_result + 1] = digit if n <= 0 then break end end end return int_result, fractional_result, sign end

function utils.negabaseCarry(int_digits, fractional_digits, destination_base, sign) if math.abs(fractional_digits[1]or 0) > 0 and (sign or 0) > 0 then int_digits[#int_digits] = int_digits[#int_digits] + 1 end local carry = 0 local abs_base = utils.round(math.abs(destination_base)) for i=#fractional_digits,1,-1 do local d = utils.round(fractional_digits[i]) + carry carry = 0 if d >= abs_base then carry = i%2 and -1 or 1 d = d - abs_base end if d < 0 then carry = i%2 and 1 or -1 d = d + abs_base end fractional_digits[i] = utils.round(d) end local j = 0 for i=#int_digits,1,-1 do j = #int_digits - i local d = utils.round(int_digits[i]) + carry carry = 0 if d >= abs_base then carry = j%2 and -1 or 1 d = d - abs_base end if d < 0 then carry = j%2 and 1 or -1 d = d + abs_base end int_digits[i] = utils.round(d) end while math.abs(carry) > 0 do j = j + 1 local d = utils.round(carry) carry = 0 if d >= abs_base then carry = j%2 and -1 or 1 d = d - abs_base end if d < 0 then carry = j%2 and 1 or -1 d = d + abs_base end table.insert(int_digits, 1, utils.round(d)) end for i=1,#int_digits-1 do if int_digits[1] == 0 then table.remove(int_digits, 1) end end return int_digits, fractional_digits end

local function complexBase2Decimal(num, imag, base) if type(cmath.constructor) ~= type(tostring) then cmath = require("Module:Complex Number").cmath.init()end local base = cmath.constructor(base) if not base then return nil end num = mw.text.trim(num) local sign = 1 local first_sign = mw.ustring.sub(num,1,1) --讀取正負號 if first_sign == '+' or first_sign == '-' or first_sign == '−' then num = mw.ustring.sub(num,2,-1) if first_sign == '-' or first_sign == '−' then sign = -1 end end if type(lib_calc._getNumString) ~= type(tostring) then lib_calc = require('Module:Complex_Number/Calculate')end local int_digits, fractional_digits = lib_calc._getNumString(num, true) local result = cmath.constructor(utils.toDecimalComplex(int_digits, fractional_digits, imag, base)) if sign < 0 then result = result * -1 end return result end

function utils.complexBaseConvert(num, to, from, digs, precision) if mw.ustring.find(to..' '..from, "[%+%-−%d]i") then if type(cmath.constructor) ~= type(tostring) then cmath = require("Module:Complex Number").cmath.init()end num = mw.ustring.gsub(num, '−', '-') to = mw.ustring.gsub(to, '−', '-') from = mw.ustring.gsub(from, '−', '-') local cto, cfrom = cmath.constructor(tostring(to)), cmath.constructor(tostring(from)) cfrom = cfrom or cmath.constructor(10)

if cto and cfrom then local number = tostring(num) number = mw.text.trim(number) --轉換為十進制 if cmath.abs(cmath.im(cfrom)) < 1e-14 and cmath.abs(cmath.re(cfrom)) > 0 then local check_number = num if not mw.ustring.find(check_number,"^[%+%-−]") then check_number = '+'..num end number = mw.ustring.gsub(check_number, "[%+%-−][%a%d%.,;:]+", function(number_part) if type(bignum.convertBase) ~= type(tostring)then bignum = require(main_module)end local is_imag = (mw.ustring.sub(number_part,-1,-1) == 'i') local convert_number = is_imag and mw.ustring.sub(number_part,1,-2) or number_part if convert_number == or convert_number == '+' or convert_number == '-' or convert_number == '−' then convert_number = convert_number..'1' end convert_number = bignum.convertBase(convert_number, 10, from)..(is_imag and 'i' or ) if not mw.ustring.find(convert_number,"^[%+%-−]") then convert_number = '+'..convert_number end return mw.ustring.gsub(convert_number, '−', '-') end) else local check_number = num if not mw.ustring.find(check_number,"^[%+%-−]") then check_number = '+'..num end number = mw.ustring.gsub(check_number, "[%+%-−][%a%d%.,;:]+", function(number_part) if type(lib_calc.scientific2number) ~= type(tostring) then lib_calc = require('Module:Complex_Number/Calculate')end local is_imag = (mw.ustring.sub(number_part,-1,-1) == 'i') local convert_number = is_imag and mw.ustring.sub(number_part,1,-2) or number_part convert_number = mw.ustring.gsub(convert_number, '−', '-') if convert_number == or convert_number == '+' or convert_number == '-' or convert_number == '−' then convert_number = convert_number..'1' end convert_number = complexBase2Decimal(convert_number, is_imag, cfrom) convert_number = tostring(convert_number) --跳脫科學記號,避免加與減和科學記號混淆 convert_number = mw.ustring.gsub(convert_number, "[Ee]%+?(%d)", "F%1") convert_number = mw.ustring.gsub(convert_number, "[Ee]%-(%d)", "D%1") if not mw.ustring.find(convert_number,"^[%+%-−]") then convert_number = '+'..convert_number end --還原科學記號為一般數字 convert_number = mw.ustring.gsub(convert_number, "([%+%-−])([%a%d%.,;:]+)", function(number_sign_part,number_value_part) local is_part_imag = (mw.ustring.sub(number_value_part,-1,-1) == 'i') local number_value_part_real = is_part_imag and mw.ustring.sub(number_value_part,1,-2) or number_value_part number_value_part_real = mw.ustring.gsub(number_value_part_real, "[DdFf]", function(Evalue) return ({D='e-',d='e-',F='e+',f='e+'})[Evalue] end) return number_sign_part..lib_calc.scientific2number(number_value_part_real, true)..(is_part_imag and 'i' or ) end) return mw.ustring.gsub(convert_number, '−', '-') end) end number = cmath.constructor(number) if not number then error(mw.ustring.format("轉換失敗:'%s' 不是有效的數字。",tostring(num)), 2) return nil end local int_digits, fractional_digits = {}, {} if cmath.abs(cto) <= 1 then return nil elseif cmath.abs(cmath.re(cto)) < 1e-14 then local to_im = cmath.im(cto) local to_im_sq = to_im * to_im if to_im_sq > 1 then local real, imag = cmath.re(number), cmath.i * cmath.im(number) imag = imag * cmath.i * to_im local function convert_part(num_val, base, frac_precision) local num_str = tostring(num_val) local sign = 1 local first_sign = mw.ustring.sub(num_str,1,1) --讀取正負號 if first_sign == '+' or first_sign == '-' or first_sign == '−' then num_str = mw.ustring.sub(num_str,2,-1) if first_sign == '-' or first_sign == '−' then sign = -1 end end if type(lib_calc._getNumString) ~= type(tostring) then lib_calc = require('Module:Complex_Number/Calculate')end local int_digits, fractional_digits = lib_calc._getNumString(num_str, true) if base < 0 and sign < 0 then for i=1,#int_digits do int_digits[i] = -int_digits[i]end for i=1,#fractional_digits do fractional_digits[i] = -fractional_digits[i]end end if utils.isInt(base) then int_digits = utils._convertBase(int_digits, 10, base, false) fractional_digits = utils._convertBase(fractional_digits, 10, base, true, tonumber(frac_precision<0 and or frac_precision)) if #int_digits == 0 then int_digits[1] = 0 end if base < 0 then int_digits, fractional_digits = utils.negabaseCarry(int_digits, fractional_digits, base, sign)end else int_digits, fractional_digits = utils.real_negabase(int_digits, fractional_digits, 10, base, 1) end return int_digits, fractional_digits end local function revert(x) rev = {} for i=#x, 1, -1 do table.insert(rev, x[i])end return rev end local real_int, real_frac = convert_part(cmath.re(real), -to_im_sq, precision) local imag_int, imag_frac = convert_part(cmath.re(imag), -to_im_sq, precision) table.insert(imag_frac, 1, imag_int[#imag_int]) table.remove(imag_int, #imag_int) if utils.is_zero(imag_frac) then imag_frac = {} end real_int, imag_int = revert(real_int), revert(imag_int) for i=1,math.max(#real_int, #imag_int) do table.insert(int_digits,1,real_int[i] or 0) table.insert(int_digits,1,imag_int[i] or 0) end if int_digits[1] == 0 then table.remove(int_digits,1) end for i=1,math.max(#real_frac, #imag_frac) do table.insert(fractional_digits,imag_frac[i] or 0) table.insert(fractional_digits,real_frac[i] or 0) end if fractional_digits[#fractional_digits] == 0 then table.remove(fractional_digits,#fractional_digits) end end elseif cmath.abs(cmath.re(cto)) >= 1 and cmath.abs(cmath.im(cto)) < 1e-14 then local real, imag = cmath.re(number), cmath.im(number) if type(bignum.convertBase) ~= type(tostring)then bignum = require(main_module)end local real_result, imag_result = bignum.convertBase(real, cmath.re(cto), 10, digs, precision), bignum.convertBase(imag, cmath.re(cto), 10, digs, precision) local real_is0, imag_is0 = ((tonumber(real_result)or 1) == 0), ((tonumber(imag_result)or 1) == 0) if imag_is0 then return real_result, elseif real_is0 and not imag_is0 then return ((math.abs(tonumber(({mw.ustring.gsub(imag_result, '−', '-')})[1]) or 0) ~= 1) and imag_result or ({mw.ustring.gsub(imag_result,'1',)})[1])..'i', end local check_sign = mw.ustring.sub(imag_result,1,1) return real_result .. ((check_sign == '+' or check_sign == '-' or check_sign == '−') and or '+') .. ((math.abs(tonumber(({mw.ustring.gsub(imag_result, '−', '-')})[1]) or 0) ~= 1) and imag_result or ({mw.ustring.gsub(imag_result,'1',)})[1]) ..'i', elseif utils.isInt(cmath.re(cto)) and utils.isInt(cmath.im(cto)) and cmath.abs(cto) > 1 then --尚不知道其他高斯整數底數的非整數轉換演算法。部分高斯整數底數無法轉換 local real, imag = cmath.re(number), cmath.im(number) local function complex_div_quotient_remainder(input_number, base) local base_real, base_imag = cmath.re(base), cmath.im(base) local max_remainder = base_real * base_real + base_imag * base_imag for i=0,max_remainder-1 do local check_quotient = (input_number-i) / base if utils.isInt(cmath.re(check_quotient)) and utils.isInt(cmath.im(check_quotient)) then return check_quotient, i end end end local int_number = cmath.ceil(number) local frac_number = number - int_number if cmath.abs(frac_number) > 1e-14 then --阻止非高斯整數進行轉換,因為目前演算法不支援 error(mw.ustring.format("轉換失敗:底數 '%s' 不支援非高斯整數 '%s' 的轉換。",tostring(to), tostring(num)), 2) return nil end local tk = (utils.myceil(math.log(cmath.abs(number))/math.log(cmath.abs(cto))) + 1) * 4 + 4 local do_number = int_number local counter = 0 while cmath.abs(do_number) > 0 do local quotient, remainder = complex_div_quotient_remainder(do_number, cto) do_number = quotient table.insert(int_digits,1,remainder)

counter = counter + 1 if counter > tk then --轉換到變成無窮迴圈,視為失敗 error(mw.ustring.format("轉換失敗:無法將 '%s' 轉換為底數 '%s' 的進制。", tostring(num), tostring(to)), 2) return nil end end if #int_digits == 0 then int_digits[1] = 0 end else return nil end local max_digs = 0 for i=1,#int_digits do if int_digits[i] > max_digs then max_digs = int_digits[i] end end for i=1,#fractional_digits do if fractional_digits[i] > max_digs then max_digs = fractional_digits[i] end end

if #int_digits < digs then --補齊整數位數 local lose_digs = digs - #int_digits for i=1,lose_digs do table.insert(int_digits, 1, 0) end end if #fractional_digits < precision then --補齊小數位數 local lose_digs = precision - #fractional_digits for i=1,lose_digs do fractional_digits[#fractional_digits+1] = 0 end end local int_result, fractional_result = utils.printAllDigit(int_digits, max_digs + 1, -1, 0, false), utils.printAllDigit(fractional_digits, max_digs + 1, precision, 0, true) return int_result, fractional_result end end return nil end

function utils.factorial(n) local result = 1 for i=1,n do result = result * i end if n<0 then for i=1,-n do result = result / i end end --提供給阶乘进制 負的用除的 return result end

utils.specialBaseData = { ['!']={ name = "!", display = "!", page = "阶乘进制", digitsplit = ":", point = ".", placeValue = function(this, digit_id) return utils.factorial(digit_id)end, baseValue = function(this, digit_id) return (digit_id < 0) and -digit_id or (digit_id + 1) end, printDigit = function(this, digit)return tostring(digit) end, needtoDecimal = false, convertBase = utils._convertBase, }, ['#']={ name = "#", display = "#", page = "质数阶乘进制", digitsplit = ":", point = ".", placeValue = function(this, digit_id) if not lib_fact.primeIndex then lib_fact = require("Module:Factorization") end local result = 1 for i=1,digit_id do result = result * ((i-1<=0) and 1 or lib_fact.primeIndex(i-1)) end if digit_id<0 then for i=1,-digit_id do result = result / ((i-1<=0) and 1 or lib_fact.primeIndex(i-1)) end end return result end, baseValue = function(this, digit_id) if not lib_fact.primeIndex then lib_fact = require("Module:Factorization") end return (digit_id < 0) and ((-digit_id<=1) and 1 or lib_fact.primeIndex(-digit_id-1)) or ((digit_id<=0) and 1 or lib_fact.primeIndex(digit_id)) end, printDigit = function(this, digit)return tostring(digit) end, needtoDecimal = false, convertBase = utils._convertBase, }, ['!0']={ --以0-9A-Z表達的阶乘进制 (遇到超過36位數可能會出現亂碼) name = "!0", display = "!", page = "阶乘进制", digitsplit = "", point = ".", placeValue = function(this, digit_id) return utils.factorial(digit_id)end, baseValue = function(this, digit_id)return (digit_id < 0) and -digit_id or (digit_id + 1) end, printDigit = function(this, digit) return utils.printAZ(digit) end, needtoDecimal = false, convertBase = utils._convertBase, }, ['!-']={ --以0-9A-Z表達的阶乘进制並省略個位數 (遇到超過36位數可能會出現亂碼) name = "!-", --oeis:A007623 display = "!", page = "阶乘进制", digitsplit = "", point = ".", placeValue = function(this, digit_id) return utils.factorial((digit_id < 0) and digit_id or (digit_id + 1))end, baseValue = function(this, digit_id)return (digit_id < 0) and -digit_id or (digit_id + 2) end, printDigit = function(this, digit) return utils.printAZ(digit) end, needtoDecimal = false, convertBase = utils._convertBase, }, fib={ name = "fib", display = "fib", page = "斐波那契进制", digitsplit = "", point = ".", placeValue = function(this, an) local sqrt5 = math.sqrt(5) local phi = (sqrt5 + 1) * 0.5 local fib_val = math.floor(math.pow(phi, math.abs(an)+((an < 0) and 2 or 1)) / sqrt5 + 0.5) return (an < 0) and (1/fib_val) or fib_val end, baseValue = function(this, digit_id)return 1 end, printDigit = function(this, digit)return tostring(digit) end, needtoDecimal = true, convertBase = utils.fibonacci_coding, }, ["fib-"]={ name = "fib-", display = "fib", page = "斐波那契进制", digitsplit = "", point = ".", placeValue = function(this, an) local sqrt5 = math.sqrt(5) local phi = (sqrt5 + 1) * 0.5 local fib_val = math.floor(math.pow(phi, math.abs(an)+2) / sqrt5 + 0.5) return (an < 0) and (1/fib_val) or fib_val end, baseValue = function(this, digit_id)return 1 end, printDigit = function(this, digit)return tostring(digit) end, needtoDecimal = true, convertBase = function(int_digits, original_base, _destination_base, fractional_flag, total_digit) local result = utils.fibonacci_coding(int_digits, original_base, _destination_base, fractional_flag, total_digit) if fractional_flag then return result end table.remove(result,#result) return result end, }, fibcode={ name = "fibcode", display = "fib code", page = "斐波那契编码", digitsplit = "", point = ".", placeValue = function(this, an) local sqrt5 = math.sqrt(5) local phi = (sqrt5 + 1) * 0.5 return math.floor(math.pow(phi, an+1) / sqrt5 + 0.5) end, baseValue = function(this, digit_id)return 1 end, printDigit = function(this, digit)return tostring(digit) end, needtoDecimal = true, convertBase = function(int_digits, original_base, _destination_base, fractional_flag, total_digit) return utils.fibonacci_coding(int_digits, original_base, _destination_base, fractional_flag, total_digit, true) end, }, ContinuedFraction={ name = "ContinuedFraction", display = "ContinuedFraction", page = "连分数", digitsplit = ",", point = ";", placeValue = function(this, an)return 1 end, baseValue = function(this, digit_id)return 1 end, printDigit = function(this, digit)return tostring(digit) end, needtoDecimal = true, convertBase = utils.ContinuedFraction, }, } utils.specialBaseData['!'] = utils.specialBaseData['!'] utils.specialBaseData['阶乘'] = utils.specialBaseData['!'] utils.specialBaseData['阶乘进制'] = utils.specialBaseData['!'] utils.specialBaseData['階乘'] = utils.specialBaseData['!'] utils.specialBaseData['階乘進制'] = utils.specialBaseData['!'] utils.specialBaseData['階乘進位'] = utils.specialBaseData['!'] utils.specialBaseData['斐波那契进制'] = utils.specialBaseData.fib utils.specialBaseData['斐波那契進制'] = utils.specialBaseData.fib utils.specialBaseData['斐波那契编码'] = utils.specialBaseData.fibcode utils.specialBaseData['斐波那契編碼'] = utils.specialBaseData.fibcode utils.specialBaseData['fib code'] = utils.specialBaseData.fibcode utils.specialBaseData['斐波那契'] = utils.specialBaseData.fib utils.specialBaseData['連分數'] = utils.specialBaseData.ContinuedFraction utils.specialBaseData['连分数'] = utils.specialBaseData.ContinuedFraction utils.specialBaseData['continued fraction'] = utils.specialBaseData.ContinuedFraction utils.specialBaseData['Continued Fraction'] = utils.specialBaseData.ContinuedFraction

function utils.getPlaceValue(base, digit_id) local special_base_data = utils.getSpecialBase(base) if special_base_data then return special_base_data:placeValue(digit_id) else return math.pow(base, digit_id) end end

function utils.getBaseValue(base, digit_id) local special_base_data = utils.getSpecialBase(base) if special_base_data then return special_base_data:baseValue(digit_id) else return base end end

function utils.getSpecialBase(base) local base_string = mw.text.trim(tostring(base)) if utils.isNaN(base) then error(string.format("底數不能為 '%s'", base_string),2) end local num_base = utils.tonumber(base_string) if num_base then return nil end local special_base_data = utils.specialBaseData[base] if special_base_data then return special_base_data end if mw.ustring.find(base_string, '[,;]') then local point, split = '.', local point_loaded = false base_string = mw.ustring.gsub(base_string, ' +', ) local base_name = base_string local az_digits = false if not mw.ustring.match(mw.ustring.sub(base_string, -2),'[%d∞]+') then split = mw.ustring.sub(base_string, -2, -2) point = mw.ustring.sub(base_string, -1, -1) base_name = mw.ustring.sub(base_string, 1, -3) if split == point and split == '.' then split = az_digits = true end point_loaded = true end local int_frac, int_base = mw.text.split(base_name..';', ';') int_base = mw.text.split(int_frac[1], ',') local int_base_count = #int_base local load_bases = mw.text.split(base_name, '[,;]') local bases, frac_bases = {}, {} local max_base = 0 local repeat_base = false for i=1,#load_bases do local unit_base = utils.tonumber(load_bases[i]) if not unit_base then return nil end if (i > 1 and unit_base == 0) or unit_base < 0 or (not utils.isInf(unit_base) and not utils.isInt(unit_base)) then return nil, string.format("不支援非正整數的混合底數 '%s' 進制", base_name) end if math.abs(unit_base) > 36 and not point_loaded then point, split = ';', ',' end if unit_base > max_base then max_base = unit_base end if i==1 and math.abs(unit_base) < 1e-14 then repeat_base = true else if i > int_base_count then frac_bases[#frac_bases + 1] = unit_base else table.insert(bases, 1, unit_base) end end end if #bases <= 0 then bases[1] = frac_bases[1]end if #frac_bases <= 0 then frac_bases = mw.clone(bases) if repeat_base and #frac_bases > 1 then frac_bases[#frac_bases + 1] = frac_bases[1] table.remove(frac_bases, 1) end end local new_base_data = { name = base_string, display = base_name, page = "混合进制", digitsplit = split, point = point, base_list = bases, frac_base_list = frac_bases, max_base = max_base, repeat_base = repeat_base, point_loaded = point_loaded, az_digits = az_digits, placeValue = function(this, digit_id) local result = 1 for i=1,math.abs(digit_id) do local using_list = digit_id < 0 and this.frac_base_list or this.base_list local doing_index = this.repeat_base and utils.loop_mod(i, #using_list) or i result = result * (using_list[doing_index] or using_list[#using_list] or 10) end return digit_id < 0 and (1/result) or result end, baseValue = function(this, digit_id) return (digit_id < 0) and (this.frac_base_list[this.repeat_base and utils.loop_mod(-digit_id, #(this.frac_base_list)) or (-digit_id)] or this.frac_base_list[#(this.frac_base_list)] or 10) or (this.base_list[this.repeat_base and utils.loop_mod(digit_id + 1, #(this.base_list)) or (digit_id + 1)] or this.base_list[#(this.base_list)] or 10) end, printDigit = function(this, digit) if (this.point_loaded or (math.abs(max_base) > 36)) and (not this.az_digits) then return utils.tostring(digit) else return utils.printAZ(digit) end end, needtoDecimal = false, convertBase = utils._convertBase, } return new_base_data end return nil end

function utils.checkSpecialBase(base) local base_string = mw.text.trim(tostring(base)) if utils.isNaN(base) then error(string.format("底數不能為 '%s'", base_string),2) end local num_base = utils.tonumber(base_string) if num_base then return num_base end local special_base_data = utils.specialBaseData[base] if special_base_data then return special_base_data.name end if mw.ustring.find(base_string, '[,;]') then base_string = mw.ustring.gsub(base_string, ' +', ) local check_string = base_string if not mw.ustring.match(mw.ustring.sub(check_string, -2),'[%d∞]+') then check_string = mw.ustring.sub(check_string, 1, -3) end local load_bases = mw.text.split(check_string, '[,;]') for i=1,#load_bases do local check_number = utils.tonumber(load_bases[i]) if not check_number then return nil end if (i > 1 and check_number == 0) or check_number < 0 or (not utils.isInf(unit_base) and not utils.isInt(check_number)) then return nil end end return base_string end return nil end

function utils.printAZ(digit) local char_0 = mw.ustring.codepoint('0') local char_A = mw.ustring.codepoint('A') - 10 local char_a = mw.ustring.codepoint('a') - 36 local char_100 = mw.ustring.codepoint('¡') - 62 local codepoint = digit + ((digit >= 10) and ((digit >= 36) and ((digit >= 62) and char_100 or char_a) or char_A) or char_0) return mw.ustring.char(codepoint) end

function utils.print_digit(digit, base) local digit = utils.round(digit) local special_base_data = utils.getSpecialBase(base) if special_base_data then return special_base_data:printDigit(digit) elseif math.abs(tonumber(base)or 10) <= 36 then return utils.printAZ(digit) else return tostring(digit) end end

function utils.printAllDigit(digits, base, precision, _subarg, fractional_flag) local subarg = tonumber(_subarg) or 0 local special_base_data = utils.getSpecialBase(base) local result, digitcomma = , if special_base_data then digitcomma = special_base_data.digitsplit elseif math.abs(tonumber(base) or 10) > 36 then digitcomma = ',' end for i=1,#digits do if precision >= 0 and i == precision + 1 then break end if subarg < 6 then if result ~= then result = result .. digitcomma end end result = result .. utils.print_digit(digits[i], base) if subarg >= 6 and subarg < 12 then result = string.format("%s%s", result, utils.tostring(special_base_data and special_base_data:baseValue(fractional_flag and -i or (#digits-i)) or base) ) elseif subarg >= 12 and subarg < 18 then result = string.format("%s%s", result, utils.tostring(((not fractional_flag) and (#digits-i == 0)) and ((tostring(base):sub(1,1)=='!')and 0 or 1) or (special_base_data and special_base_data:baseValue(fractional_flag and -i or (#digits-i-1))) or base) ) end end return result end

function utils.toDecimal(int_digits, fractional_digits, base) local n = int_digits[#int_digits] or 0 local j = 1 for i = #int_digits-1, 1, -1 do n = n + int_digits[i] * utils.getPlaceValue(base, j) j = j + 1 end for i = 1, #fractional_digits do n = n + fractional_digits[i] * utils.getPlaceValue(base, -i) end return n end

function utils.toDecimalComplex(int_digits, fractional_digits, imag, base) if type(cmath.constructor) ~= type(tostring) then cmath = require("Module:Complex Number").cmath.init()end base = cmath.constructor(base) if not base then return nil end local n = cmath.constructor(int_digits[#int_digits]) local j = 1 for i = #int_digits-1, 1, -1 do n = n + int_digits[i] * utils.cintpow(base, j) j = j + 1 end for i = 1, #fractional_digits do n = n + fractional_digits[i] * utils.cintpow(base, -i) end n = (imag and cmath.i or cmath[1]) * n n:clean() return n end

function utils.print_base_string(int_result, fractional_result, ori_int_digits, ori_fractional_digits, sign, from, to, _subarg, prefix, suffix) local subarg = tonumber(_subarg) or 0 local special_base_data_from = utils.getSpecialBase(from) local special_base_data_to = utils.getSpecialBase(to) local point_string = (math.abs(tonumber(to) or 10) > 36) and ';' or ((special_base_data_to or{}).point or '.') if tostring(to):sub(-1,-1) == 'i' and (int_result:find(',') or (fractional_result or):find(',')) then point_string = ';'end local number_result = ((sign < 0) and '−' or ) .. (int_result == and '0' or int_result) .. (fractional_result == and or (point_string..fractional_result)) local result = (prefix or ) .. number_result .. (suffix or ) if subarg % 6 == 1 then result = string.format("%s(%s)", result, utils.tostring((special_base_data_to or{}).display or to)) elseif subarg % 6 == 2 then result = string.format("(%s)%s", result, utils.tostring((special_base_data_to or{}).display or to)) elseif subarg % 6 == 3 or subarg % 6 == 5 then local lib_num2zh = require('Module:NumberToChinese') local success, num = pcall(utils.toDecimal, ori_int_digits, ori_fractional_digits, from) if not success then --轉換失敗時 if type(bignum.convertBase) ~= type(tostring)then bignum = require(main_module)end if tonumber(to) then num = (tonumber(to) == 10) and number_result or "數字" --不支援的部分 else success, num = pcall(bignum.convertBase, number_result, 10, to) if not success then num = "數字" end --不支援的部分 end end local base_name = lib_num2zh._numberToChinese(utils.tostring(to)) if base_name == lib_num2zh.NotANumber() then base_name = utils.tostring(to) end result = mw.ustring.format("%s%s%s%s", utils.tostring(num), result, special_base_data_to and (special_base_data_to.page) or (base_name..'進制'), (subarg % 6 == 5) and or '(', utils.tostring((special_base_data_to or{}).display or to), (subarg % 6 == 5) and or ')') elseif subarg % 6 == 4 then result = string.format("%s%s", result, utils.tostring((special_base_data_to or{}).display or to)) end return result end

return utils