Various mathematical functions.
functionexport.tonumber_extended(x,base,finite_real,no_prefix)
An extended version oftonumber(), which attempts to convertx to a number. Liketonumber(), it will convert from base 10 by default, and the optional parameterbase can be used to specify a different base between 2 and 36, with the lettersA-Z (case-insensitive) representing additional digits beyond0-9. When strings contain hexadecimal notation (e.g."0x100"), base 16 is used as the default instead, but this is overridden ifbase is set to anything other than 16.
This function differs fromtonumber() in the following ways:
finite_real is set, then the function will only return finite real numbers; inputs which would normally produce ±infinity or NaN will instead producenil.no_prefix is set, then strings which start with"0x" will not be interpreted as containing hexadecimal notation, resulting innil.base is explicitly set to10, then strings in hexadecimal notation will always returnnil. This fixes a bug intonumber(), which treatsbase=10 the same asbase being unset, causing base 16 to be used ifx contains hexadecimal notation (e.g.tonumber("0x10",10) returns16, whereastonumber_extended("0x10",10) returnsnil).functionexport.to_integer(x)
Convertsx to an integer by removing the fractional portion (e.g.3.5 becomes3, and-2.9 becomes-2). This is equivalent to rounding down positive numbers and rounding up negative numbers. If conversion is not possible, returnsnil.
functionexport.sign(x,signed_0)
Returns1 ifx is positive,-1 ifx is negative, or0 ifx is0.
Ifsigned_0 is set, this function will only return either1 or-1, and will make a distinction betweensigned zeroes (+0 and-0). This is useful when a0 result could be disruptive (e.g.x%0).
functionexport.is_finite_real_number(x)
Returnstrue ifx is a finite real number, orfalse if not.
functionexport.is_integer(x)
Returnstrue ifx is an integer, orfalse if not.
functionexport.is_positive_integer(x,include_0)
Returnstrue ifx is a positive integer (or zero if theinclude_0 flag is set), orfalse if not.
functionexport.is_NaN(x)
Returnstrue isx isNaN (Not a Number), orfalse if not.
NaN is a value that has the type "number", but does not represent an actual numeric value; it has the unique property that ifx is NaN,x~=x evaluates totrue.
functionexport.log10(x)
Returns the base-10 logarithm ofx.
This function should be used instead ofmath.log10, which is deprecated and may stop working if Scribunto is updated to a more recent Lua version.
functionexport.to_hex(dec,include_prefix)
Converts a decimal number to hexadecimal. Ifinclude_prefix is set, the returned number will include the 0x prefix.
functionexport.gcd(x,...)
Returns the greatest common divisor of an arbitrary number of input numbers.
functionexport.lcm(x,...)
Returns the least common multiple of an arbitrary number of input numbers.
localexport={}localbyte=string.bytelocalceil=math.ceillocalfloor=math.floorlocalformat=string.formatlocalis_integer-- defined belowlocalmatch=string.matchlocalselect=selectlocaltonumber=tonumberlocaltonumber_ext-- defined belowlocaltostring=tostringlocaltype=typelocalINF=math.hugelocalfunctionsign(x,signed_0)ifx>0thenreturn1elseifx<0thenreturn-1elseifx==0then-- 1/(+0) is infinity and 1/(-0) is -infinity.returnsigned_0and(1/x>0and1or-1)or0end-- NaN: convert to string with a forced sign prefix, and grab the first byte.localsign=byte(format("%+f",x))returnsign==0x2Band1or-- +sign==0x2Dand-1or-- --- If there's no sign, throw an error. This shouldn't be possible, but-- avoids silent errors if it does happen.error("Internal error: cannot determine sign of "..x)end--[==[An extended version of {tonumber()}, which attempts to convert `x` to a number. Like {tonumber()}, it will convert from base 10 by default, and the optional parameter `base` can be used to specify a different base between 2 and 36, with the letters {A-Z} (case-insensitive) representing additional digits beyond {0-9}. When strings contain hexadecimal notation (e.g. {"0x100"}), base 16 is used as the default instead, but this is overridden if `base` is set to anything other than 16.This function differs from {tonumber()} in the following ways:* If `finite_real` is set, then the function will only return finite real numbers; inputs which would normally produce ±infinity or NaN will instead produce {nil}.* If `no_prefix` is set, then strings which start with {"0x"} will not be interpreted as containing hexadecimal notation, resulting in {nil}.* If `base` is explicitly set to {10}, then strings in hexadecimal notation will always return {nil}. This fixes a bug in {tonumber()}, which treats {base=10} the same as {base} being unset, causing base 16 to be used if `x` contains hexadecimal notation (e.g. {tonumber("0x10", 10)} returns {16}, whereas {tonumber_extended("0x10", 10)} returns {nil}).]==]functionexport.tonumber_extended(x,base,finite_real,no_prefix)-- TODO: tonumber() maxes out at 2^64 if the base is anything other than 10.-- TODO: support binary (0b) and octal (0o) prefixes.localn=tonumber(x,base)ifnotnorfinite_realand(n~=norn==INForn==-INF)thenreturnnil-- If `base` is explicitly set to 10 (not simply nil), or `no_prefix` is set-- and `base` is nil or 16, filter out inputs that started with hexadecimal-- prefixes. Note that if `base` is anything else, the initial "0x" will-- have been interpreted as digits by tonumber() instead of a prefix (as "x"-- can be a digit from base 34 upwards), so there's no prefix to check for.elseifbase==10orno_prefixand(base==nilorbase==16)thenreturnnotmatch(x,"^%s*[+-]?0[xX]()")andnornilendreturnnendtonumber_ext=export.tonumber_extended--[==[Converts `x` to an integer by removing the fractional portion (e.g. {3.5} becomes {3}, and {-2.9} becomes {-2}). This is equivalent to rounding down positive numbers and rounding up negative numbers. If conversion is not possible, returns {nil}.]==]functionexport.to_integer(x)x=tonumber(x)ifnot(xandx==xandx~=INFandx~=-INF)thenreturnnilelseifx%1==0thenreturnx-- Round-down positives.elseifx>=0thenreturnfloor(x)end--Round-up negatives.returnceil(x)end--[==[Returns {1} if `x` is positive, {-1} if `x` is negative, or {0} if `x` is {0}.If `signed_0` is set, this function will only return either {1} or {-1}, and will make a distinction between [[w:signed zero|signed zeroes]] ({+0} and {-0}). This is useful when a {0} result could be disruptive (e.g. {x % 0}).]==]functionexport.sign(x,signed_0)returnsign(tonumber(x)orerror(format("bad argument #1 to 'sign' (number expected, got %s)",type(x)),2),signed_0)end--[==[Returns {true} if `x` is a finite real number, or {false} if not.]==]functionexport.is_finite_real_number(x)returnxandx==xandnot(x==INForx==-INF)andtype(x)=="number"end--[==[Returns {true} if `x` is an integer, or {false} if not.]==]functionexport.is_integer(x)returnxandtype(x)=="number"andx%1==0orfalseendis_integer=export.is_integer--[==[Returns {true} if `x` is a positive integer (or zero if the `include_0` flag is set), or {false} if not.]==]functionexport.is_positive_integer(x,include_0)returnxandtype(x)=="number"and(x>0orinclude_0andx==0)andx%1==0orfalseend--[==[Returns {true} is `x` is [[w:NaN|NaN]] (Not a Number), or {false} if not.NaN is a value that has the type "number", but does not represent an actual numeric value; it has the unique property that if {x} is NaN, {x ~= x} evaluates to {true}.]==]functionexport.is_NaN(x)returnx~=xend--[==[Returns the base-10 logarithm of `x`.This function should be used instead of {math.log10}, which is deprecated and may stop working if Scribunto is updated to a more recent Lua version.]==]functionexport.log10(x)-- Structured like this so that module documentation works.locallog10=math.log10iflog10~=nilthenreturnlog10endlocallog=math.logreturnlog(10,10)==1andfunction(x)-- Lua 5.2returnlog(x,10)endorfunction(x)-- Lua 5.1returnlog(x)*0.43429448190325182765112891891660508229439700580367-- log10(e)endendexport.log10=export.log10()-- Sets the actual returned function.localfunctioninteger_error(x,param,func_name)localtype_x=type(x)error(format("bad argument #%d to '%s' (integer expected, got %s)",param,func_name,type_x=="number"andtostring(x)ortype_x),3)end--[==[Converts a decimal number to hexadecimal. If `include_prefix` is set, the returned number will include the 0x prefix.]==]functionexport.to_hex(dec,include_prefix)dec=tonumber(dec)ordecifnotis_integer(dec)theninteger_error(dec,1,"to_hex")endlocalneg=dec<0ifnegthendec=-decend-- Inputs >= 2^64 cause string.format to return "0".ifdec>=0x1p64thenerror("integer overflow in 'to_hex': cannot convert inputs with a magnitude greater than or equal to 2^64 (18446744073709551616)",2)end-- string.format treats hex numbers as unsigned, so any sign must be added manually.returnformat("%s%s%X",negand"-"or"",include_prefixand"0x"or"",dec)end--[==[Returns the greatest common divisor of an arbitrary number of input numbers.]==]functionexport.gcd(x,...)x=tonumber(x)orxifnotis_integer(x)theninteger_error(x,1,"gcd")endlocalq,args_len,integers=...,select("#",...)-- Compute p_1 = gcd(n_1, n_2), p_2 = gcd(p_1, n_3), ... i.e. compute GCD by Euclid's algorithm for the current result and the next number.fori=2,args_len+1doq=tonumber(q)orqifnotis_integer(q)theninteger_error(q,i,"gcd")elseifx~=1then-- If x is 1, validate remaining inputs.-- GCD of two integers x, q with Euclid's algorithm.whileq~=0dox,q=q,x%qendendifi<=args_lenthen-- Only create a table if absolutely necessary, as it's inefficient.ifi==2thenintegers={...}endq=integers[i]endendreturnx<0and-xorxend--[==[Returns the least common multiple of an arbitrary number of input numbers.]==]functionexport.lcm(x,...)x=tonumber(x)orxifnotis_integer(x)theninteger_error(x,1,"lcm")endlocalq,args_len,integers=...,select("#",...)-- Compute the product of all inputs as p and GCD as x.fori=2,args_len+1doq=tonumber(q)orqifnotis_integer(q)theninteger_error(q,i,"lcm")elseifx~=0then-- If x is 0, validate remaining inputs.-- Compute the product.localp=x*q-- GCD of two integers x, q with Euclid's algorithm.whileq~=0dox,q=q,x%qend-- Divide product by the GCD to get new LCM.x=p/xendifi<=args_lenthen-- Only create a table if absolutely necessary, as it's inefficient.ifi==2thenintegers={...}endq=integers[i]endendreturnx<0and-xorxendreturnexport