-- 计算器插件 -- author: https://github.com/ChaosAlphard local calc = {} function calc.init( env ) local config = env.engine.schema.config env.prefix = config:get_string( 'calculator/prefix' ) or 'cC' env.show_prefix = config:get_bool( 'calculator/show_prefix' ) -- set to true to show prefix in preedit area -- env.decimalPlaces = config:get_string('calculator/decimalPlaces') or '4' end local function startsWith( str, start ) return string.sub( str, 1, string.len( start ) ) == start end local function truncateFromStart( str, truncateStr ) return string.sub( str, string.len( truncateStr ) + 1 ) end local function yield_calc_cand( seg, cand_text, cand_comment, cand_preedit, show_prefix ) local cand = Candidate( 'calc', seg.start, seg._end, cand_text, cand_comment ) cand.quality = 99999 if not show_prefix then cand.preedit = cand_preedit end yield( cand ) end -- 函数表 local calcPlugin = { -- e, exp(1) = e^1 = e e = math.exp( 1 ), -- π pi = math.pi, } -- random([m [,n ]]) 返回m-n之间的随机数, n为空则返回1-m之间, 都为空则返回0-1之间的小数 local function random( ... ) return math.random( ... ) end -- 注册到函数表中 calcPlugin['rdm'] = random calcPlugin['random'] = random -- 正弦 local function sin( x ) return math.sin( x ) end calcPlugin['sin'] = sin -- 双曲正弦 local function sinh( x ) return math.sinh( x ) end calcPlugin['sinh'] = sinh -- 反正弦 local function asin( x ) return math.asin( x ) end calcPlugin['asin'] = asin -- 余弦 local function cos( x ) return math.cos( x ) end calcPlugin['cos'] = cos -- 双曲余弦 local function cosh( x ) return math.cosh( x ) end calcPlugin['cosh'] = cosh -- 反余弦 local function acos( x ) return math.acos( x ) end calcPlugin['acos'] = acos -- 正切 local function tan( x ) return math.tan( x ) end calcPlugin['tan'] = tan -- 双曲正切 local function tanh( x ) return math.tanh( x ) end calcPlugin['tanh'] = tanh -- 反正切 -- 返回以弧度为单位的点相对于x轴的逆时针角度。x是点的横纵坐标比值 -- 返回范围从−π到π (以弧度为单位),其中负角度表示向下旋转,正角度表示向上旋转 local function atan( x ) return math.atan( x ) end calcPlugin['atan'] = atan -- 反正切 -- atan( y/x ) = atan2(y, x) -- 返回以弧度为单位的点相对于x轴的逆时针角度。y是点的纵坐标,x是点的横坐标 -- 返回范围从−π到π (以弧度为单位),其中负角度表示向下旋转,正角度表示向上旋转 -- 与 math.atan(y/x) 函数相比,具有更好的数学定义,因为它能够正确处理边界情况(例如x=0) local function atan2( y, x ) return math.atan2( y, x ) end calcPlugin['atan2'] = atan2 -- 将角度从弧度转换为度 e.g. deg(π) = 180 local function deg( x ) return math.deg( x ) end calcPlugin['deg'] = deg -- 将角度从度转换为弧度 e.g. rad(180) = π local function rad( x ) return math.rad( x ) end calcPlugin['rad'] = rad -- 返回两个值, 无法参与运算后续, 只能单独使用 -- 返回m,e 使得x = m * 2^e local function frexp( x ) local m, e = math.frexp( x ) return m .. ' * 2^' .. e end calcPlugin['frexp'] = frexp -- 返回 x * 2^y local function ldexp( x, y ) return math.ldexp( x, y ) end calcPlugin['ldexp'] = ldexp -- 返回 e^x local function exp( x ) return math.exp( x ) end calcPlugin['exp'] = exp -- 返回x的平方根 e.g. sqrt(x) = x^0.5 local function sqrt( x ) return math.sqrt( x ) end calcPlugin['sqrt'] = sqrt -- y为底x的对数, 使用换底公式实现 local function log( y, x ) -- 不能为负数或0 if x <= 0 or y <= 0 then return nil end return math.log( x ) / math.log( y ) end calcPlugin['log'] = log -- e为底x的对数 local function loge( x ) -- 不能为负数或0 if x <= 0 then return nil end return math.log( x ) end calcPlugin['loge'] = loge -- 10为底x的对数 local function log10( x ) -- 不能为负数或0 if x <= 0 then return nil end return math.log10( x ) end calcPlugin['log10'] = log10 -- 平均值 local function avg( ... ) local data = { ... } local n = select( '#', ... ) -- 样本数量不能为0 if n == 0 then return nil end -- 计算总和 local sum = 0 for _, value in ipairs( data ) do sum = sum + value end return sum / n end calcPlugin['avg'] = avg -- 方差 local function variance( ... ) local data = { ... } local n = select( '#', ... ) -- 样本数量不能为0 if n == 0 then return nil end -- 计算均值 local sum = 0 for _, value in ipairs( data ) do sum = sum + value end local mean = sum / n -- 计算方差 local sum_squared_diff = 0 for _, value in ipairs( data ) do sum_squared_diff = sum_squared_diff + (value - mean) ^ 2 end return sum_squared_diff / n end calcPlugin['var'] = variance -- 阶乘 local function factorial( x ) -- 不能为负数 if x < 0 then return nil end if x == 0 or x == 1 then return 1 end local result = 1 for i = 1, x do result = result * i end return result end calcPlugin['fact'] = factorial -- 实现阶乘计算(!) local function replaceToFactorial( str ) -- 替换[0-9]!字符为fact([0-9])以实现阶乘 return str:gsub( '([0-9]+)!', 'fact(%1)' ) end -- 简单计算器 function calc.func( input, seg, env ) if not seg:has_tag( 'calculator' ) or input == '' then return end -- 提取算式 local express = truncateFromStart( input, env.prefix ) if express == '' then return end -- 防止用户写错了正则表达式造成错误 local code = replaceToFactorial( express ) local success, result = pcall( load( 'return ' .. code, 'calculate', 't', calcPlugin ) ) if success and result and (type( result ) == 'string' or type( result ) == 'number') and #tostring( result ) > 0 then yield_calc_cand( seg, result, '', express, env.show_prefix ) yield_calc_cand( seg, express .. '=' .. result, '', express, env.show_prefix ) else yield_calc_cand( seg, express, '解析失败', express, env.show_prefix ) yield_calc_cand( seg, code, '入参', express, env.show_prefix ) end end return calc