-- Constants local MAXIMUM_INT = 2^53 -- The maximum double for where all integers can be represented exactly. local MAXIMUM_ZERO = 10^-7 -- Used when attempting to determine fraction. Anything below is counted as 0. -------------------------------------------------------------------------------- -- Util local function is_integer (n) -- Predicate. Neither +inf, -inf nor nan are integer. return n == math.floor(n) and n ~= 1/0 and n ~= -1/0 end local function factorial (n) -- Returns the factorial of n. -- That is n! = n * (n-1) * (n-2) * ... * 1 local a = 1 for i = 2, n do a = a * i end return a end local function calculate_fraction (n) -- Returns x and y such that x/y = n. If none could be found, returns nil. local a, b = 1, n % 1 while MAXIMUM_ZERO < b and a <= MAXIMUM_INT do local r = math.pow(b, -1) a, b = a * r, r % 1 -- Invariant: n * a / a = n end -- Check the values make sense. local numerator, denumberator = math.floor(n * a), math.floor(a) if numerator / denumberator == n then return numerator, denumberator end end local MATH_SHORTHAND = { -- Only used if options.math_shorthand = true ['0/0'] = 'nan', ['1/0'] = '∞', ['-1/0'] = '-∞', ['math.pi'] = 'π', ['math.exp(1)'] = 'e', } -------------------------------------------------------------------------------- -- Generate special number table -- TODO: Restructure this. local SPECIAL_NUMBER = {} do SPECIAL_NUMBER[ 1/0] = '1/0' SPECIAL_NUMBER[math.pi] = 'math.pi' SPECIAL_NUMBER[math.exp(1)] = 'math.exp(1)' for i = -10, -6 do SPECIAL_NUMBER[math.pow(10, i)] = '10^'..i end for i = -15, -7 do SPECIAL_NUMBER[math.pow( 2, i)] = '2^'..i end for i = 5, 308 do SPECIAL_NUMBER[math.pow(10, i)] = '10^'..i end for i = 17, 1023 do SPECIAL_NUMBER[math.pow( 2, i) ] = '2^'..i --SPECIAL_NUMBER[math.pow( 2, i) - 1] = '2^'..i..'-1' --SPECIAL_NUMBER[math.pow( 2, i) + 1] = '2^'..i..'+1' end for i = 9, 170 do SPECIAL_NUMBER[factorial(i)] = i..'!' end for i = 1, 100 do local sqrt = math.sqrt(i) if not is_integer(sqrt) then SPECIAL_NUMBER[1/sqrt] = '1/math.sqrt('..i..')' SPECIAL_NUMBER[sqrt] = 'math.sqrt('..i..')' end end for i = 1, 100 do local log = math.log(i) if not is_integer(log) then SPECIAL_NUMBER[log] = 'math.log('..i..')' end end end -------------------------------------------------------------------------------- local function format_number (n) -- Returns a string of n formatted as to allow easy back into a lua interpreter. if n ~= n then return '0/0' elseif n < 0 then return '-' .. format_number(-n) elseif SPECIAL_NUMBER[n] then return SPECIAL_NUMBER[n] end -- Maybe it's an integer? if is_integer(n) then return tostring(n) end -- Maybe it's a fraction? local numerator, denumberator = calculate_fraction(n) if numerator then return format_number(numerator)..'/'..format_number(denumberator) end return ( tostring(n):gsub('e%+?', '*10^') ) -- Parantheses to return first result. end return function (value, options, depth, l) l[#l+1] = format_number(value) if options.math_shorthand then l[#l] = MATH_SHORTHAND[ l[#l] ] end end