119 lines
3.2 KiB
Lua
119 lines
3.2 KiB
Lua
|
|
||
|
-- 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
|