diff --git a/init.lua b/init.lua index 6063b98..254ef11 100644 --- a/init.lua +++ b/init.lua @@ -1,2 +1 @@ - -return require("pretty.pretty") +return require 'pretty.pretty' diff --git a/number.lua b/number.lua index 9fbfd92..edc44af 100644 --- a/number.lua +++ b/number.lua @@ -1,4 +1,6 @@ +local utf8 = require "utf8" + -- Constants local MAXIMUM_INT = 2^53 -- The maximum double for where all integers can be represented exactly. @@ -46,24 +48,10 @@ local function calculate_fraction (n) end end -local UNICODE_SUPERSCRIPT = { - ['0'] = '⁰', ['1'] = '¹', ['2'] = '²', ['3'] = '³', ['4'] = '⁴', - ['5'] = '⁵', ['6'] = '⁶', ['7'] = '⁷', ['8'] = '⁸', ['9'] = '⁹', - ['-'] = '⁻', ['+'] = '⁺', ['='] = '⁼', ['('] = '⁽', [')'] = '⁾', -} -local function to_superscript (n) - return tostring(n):gsub('.', function (a) return UNICODE_SUPERSCRIPT[a] end) -end - -local UNICODE_CHAR_PATTERN = '[\01-\127\192-\255][\128-\191]*' -local function unicode_len (str) - local len = 0 - for char in str:gmatch(UNICODE_CHAR_PATTERN) do len = len + 1 end - return len -end - -------------------------------------------------------------------------------- +local format_num + local SPECIAL_NUMBER = { -- x = ∞ { est = function (...) return ... end, @@ -71,6 +59,12 @@ local SPECIAL_NUMBER = { repr = function (a) return '1/0' end, short = function (a) return '∞' end, }, + -- x = a/b + { est = calculate_fraction, + real = function (a, b) return b ~= 1 and (a/b) end, + repr = function (a, b) return format_num(a)..'/'..format_num(b) end, + short = function (a, b) return format_num(a)..'/'..format_num(b) end, + }, -- Factorial { est = function (n) return inverse_factorial(n) end, real = function (a) return factorial(a) end, @@ -81,19 +75,19 @@ local SPECIAL_NUMBER = { { est = function (n) return math.log(n)/math.log(2) end, real = function (a) return 2^a end, repr = function (a) return '2^'..a end, - short = function (a) return '2'..to_superscript(a) end, + short = function (a) return '2'..utf8.superscript(a) end, }, -- x = 10^a { est = function (n) return math.log(n)/math.log(10) end, real = function (a) return 10^a end, repr = function (a) return '10^'..a end, - short = function (a) return '10'..to_superscript(a) end, + short = function (a) return '10'..utf8.superscript(a) end, }, -- x = 1/√a { est = function (n) return 1/(n^2) end, real = function (a) return 1/math.sqrt(a) end, repr = function (a) return ('1/math.sqrt(%i)'):format(a) end, - short = function (a) return '1/√'..a end, + short = function (a) return '1/√'..utf8.overline(a) end, }, -- x = lg a { est = function (n) return math.exp(n) end, @@ -105,7 +99,7 @@ local SPECIAL_NUMBER = { { est = function (n) return math.log(n) end, real = function (a) return math.exp(a) end, repr = function (a) return ('math.exp(%i)'):format(a) end, - short = function (a) return a == 1 and 'ℯ' or 'ℯ'..to_superscript(a) end, + short = function (a) return a == 1 and 'ℯ' or 'ℯ'..utf8.superscript(a)end, }, -- x = aπ { est = function (n) return n/math.pi end, @@ -117,7 +111,7 @@ local SPECIAL_NUMBER = { { est = function (n) return n^2 end, real = function (a) return math.sqrt(a) end, repr = function (a) return ('math.sqrt(%i)'):format(a) end, - short = function (a) return '√'..a end, + short = function (a) return '√'..utf8.overline(a) end, }, -- a = x { est = function (n) return n end, @@ -129,39 +123,29 @@ local SPECIAL_NUMBER = { -------------------------------------------------------------------------------- -local LONG_ASS_CONSTANT = '___________________________________________________' - -local function format_number (n, shorthand) +function format_num (n, shorthand) if n ~= n then return shorthand and 'NaN' or '0/0' - elseif n < 0 then return '-' .. format_number(-n, shorthand) + elseif n < 0 then return '-' .. format_num(-n, shorthand) end -- Finding the shortest - local shortest, length = LONG_ASS_CONSTANT, unicode_len(LONG_ASS_CONSTANT) + local shortest, length = nil, math.huge local function alternative_repr (repr) - local repr_len = unicode_len(repr) + local repr_len = utf8.width(repr) if repr_len < length then shortest, length = repr, repr_len end end -- Maybe it's a "special" number? for _, special_number_tests in pairs(SPECIAL_NUMBER) do - local a = special_number_tests.est(n) - if a then - local a_near = math.floor(a + 0.5) - if n == special_number_tests.real(a_near) then - alternative_repr( special_number_tests[shorthand and 'short' or 'repr'](a_near) ) + local a = { special_number_tests.est(n) } + if a[1] then + for i = 1, #a do a[i] = math.floor(a[i] + 0.5) end + if n == special_number_tests.real(unpack(a)) then + alternative_repr( special_number_tests[shorthand and 'short' or 'repr'](unpack(a)) ) end end end - -- Maybe it's a fractional number? - do - local numerator, denumberator = calculate_fraction(n) - if numerator and denumberator ~= 1 then - alternative_repr( format_number(numerator)..'/'..format_number(denumberator) ) - end - end - -- Maybe it's a decimal number? alternative_repr( tostring(n):gsub('([^e]+)e%+?(%-?)0+', function(a, b) return (a == '1' and '' or a..'*')..'10^'..b end)) @@ -170,5 +154,5 @@ local function format_number (n, shorthand) end return function (value, options, depth, l) - l[#l+1] = format_number(value, options.math_shorthand) + l[#l+1] = format_num(value, options.math_shorthand) end diff --git a/test/test_number.lua b/test/test_number.lua index 1497f2a..97f6b36 100644 --- a/test/test_number.lua +++ b/test/test_number.lua @@ -101,13 +101,13 @@ number_test { number_test { input = math.sqrt(8), expect = 'math.sqrt(8)', - shorthand = '√8', + shorthand = '√̅8', } number_test { input = 1/math.sqrt(8), expect = '1/math.sqrt(8)', - shorthand = '1/√8', + shorthand = '1/√̅8', } number_test { @@ -169,6 +169,12 @@ number_test { -------------------------------------------------------------------------------- +number_test { + -- A half should always be represented using 1/2, never with 2⁻¹. + input = 1/2, + expect = '1/2', +} + format_test { input = { 1/2, 1/3, 1/4, 1/5 }, expect = '{ 1/2, 1/3, 1/4, 1/5 }',