I was actually planning to make this with the previous version before my previous account was terminated, definitely will work on this next!
I remember I tried to make a pi generator with lebreniz formula. And it was innacurate as hell. Thank you for this.
By the way, in the integral function, you can lower the number “1e-5” so something like 1e-8, the function will take longer to run since its a loop, however this will get you better estimates of pi, or whatever you’re attempting to calculate
Hi, it’s me again. I tried doing some optimizations on your Solver function, and I managed to shave off a considerable amount of processing time.
Standalone module of the function with my changes
local module = {}
type math = (number) -> (number)
local flr = math.floor
local ts = tostring
local strL = string.lower
local inf = math.huge
function round(n: number, decimal: number?): number
local factor: number = decimal or 1
return flr(n * factor + .5) / factor
end
function module.Solve(f: math, iterations: number?): {number} --2nd parameter allows for user-set amount of iterations
local iterations = iterations or 1e3 --default iteration amount of 1000
local t: {number} = {}
for i = -20, 20, .1 do
table.insert(t, i)
end
for ii = 1, iterations do
for i, a in ipairs(t) do
local fa: number = f(a)
local num: number = a - 1e-5*fa / (f(a + 1e-5) - fa)
local num2: number = round(num, 1e14)
t[i] = if strL(ts(num2)) == 'nan' then inf else if ii == iterations then num2 else num
end
end
local bl: {true} = {}
local n: {number} = {}
for _, v in ipairs(t) do
local num: number = round(v, 1e10)
if not bl[num] then
bl[num] = true
table.insert(n, num)
end
end
table.sort(n)
return n
end
return module
As for actual output, it’s basically the same. The loss of precision should be negligible for any practical applications.
Edit 2: made some more changes to the script for even more performance
I definitely overlooked performance when making the function, this will be apart of the next version of the module. Thanks for the help once again!
Update 2 - Miniscule Updates & a new module
Thursday, June 30th, 2022
Algebra
Lambert W function
Purpose: find the value of x for an equation in the form of x*e^x when its equal to some number y
Parameters:
- Number - y
Output: Table
Explanation:
-
This uses the solver function
Lambert W function - Wikipedia
Example:
local x = module.lambert(5*math.exp(5)) -- x = 5
local y = module.lambert(3*math.exp(3)) -- y = 3
local z = module.lambert(2) -- z = 0.8526055020137
Imaginary Library
To Array
Purpose: convert a number (complex or not) to an array in the form of {a,b} from the form “a+bi”
Parameters:
- String/Number
Output: Table
Explanation:
- “1+i” will convert to {1,1}, “5-2i” will convert to {5,-2}, “i” converts to {0,1}, this is a general idea
Example:
local x = complex.toArray("1+i") -- x = {1,1}
local y = complex.toArray("5-2i") -- y = {5,-2}
local z = complex.toArray("i") -- z = {0,1}
To String
Purpose: convert an array to an string/number in the form of “a+bi” from the form {a,b}
Parameters:
- Table
Output: String/Number
Explanation:
- {1,1} will convert to “1+i”, {5,-2}will convert to “5-2i” , {0,1} converts to “i”, this is a general idea
Example:
local x = complex.toString({1,1}) -- x = "1+i"
local y = complex.toString({5,-2}) -- y = "5-2i"
local z = complex.toString({0,1}) -- z = "i"
- Solver function was very inefficient, thank you @Prototrode for bringing this to my attention and offering an improved version of the function
- There were calls to print random variables scattered around the module due to debugging, those are all removed
- Addition and Multiplication with complex values now support more than two inputs, these inputs can also be strings such as “1-2i” or “i”
- All imaginary library functions that return a complex value, will now be more readable when the imaginary term has a negative coefficient, thanks to the toString and toArray functions.
Before: "9+ -33i"
Now: "9-33i"
Ive created a new module for graphing functions called Graphit which allows you to graph any function you’d like.
Update 3 - More Complex Number Support
Saturday, July 2nd, 2022
Algebra
Tetration
Purpose: calculate x^x, a certain amount of times
Parameters:
- Number -
- Iteration Count - how many times is x taken to the xth power (OPTIONAL) || Defaulted to 2
Output: Number/Table
Explanation:
-
if you input 5,2 as the parameters, it will return 5^5, if you input 2,4, it will return 2^2^2^2.
Heres more on tetration:
Tetration - Wikipedia
Example:
local x = module.tetration(math.sqrt(2),10000) -- x = 2 -- fun fact the infinite tetration of root 2 is 2!!
local y = module.tetration(3) -- y = 3^3=27
local z = module.tetration(i,10000) -- z = 0.43828293672702395+0.3605924718713796i
Imaginary Library
To Real
Purpose: convert a complex number into its real part
Parameters:
- Number
Output: String/Number
Explanation:
- The real part of 1+i is 1, so it returns 1
Example:
local x = complex.Re(1+i) -- x = 1
local y = complex.Re(5-2*i) -- y = 5
local z = complex.Re(i) -- z = 0
To Imaginary
Purpose: convert a complex number into its imaginary part
Parameters:
- Number
Output: String/Number
Explanation:
- The imaginary part of 1+2i is 2, so it returns 2
Example:
local x = complex.Im(1+i) -- x = 1
local y = complex.Im(5-2*i) -- y = -2
local z = complex.Im(i) -- z = 1
Ive updated the module so that common math functions are compatible with inputs and outputs of complex numbers
- Sine (sin)
- Cosine (cos)
- Tangent (tan)
- Arcsine (asin)
- Arccosine (acos)
- Arctangent (atan)
- Sine Hyperbolic (sinh)
- Cosine Hyperbolic (cosh)
- Tangent Hyperbolic (tanh)
- Logarithm - The base and argument can be complex and/or negative (log)
- Power (pow)
- Square Root (sqrt)
And also makes some normal functions compatible with complex numbers
- Nth Fibonacci Number (fibonacci)
- Summation/Product (summation/product)
- Vertex Calculator (vertex)
- Tetration (tetration)
- Now, you can use i as if its a number, to call it, you can do:
local i = module.Complex.i
print(i^2) -- -1
We are all gathered here to witness the removal of several complex number functions
- Addition - Due to now i being a datatype, adding is as simple as 1+i
- Multiplication - For the same reason as Additions removal
- Division - Same reason
I dont know what the next update should have, let me know if you have an idea!
It would be helpful if you mentioned some functions (especially the one in the statistics and probability section) mutates the table pointer especially if I expect it to not mutate (MathFunctions.min
, MathFunctions.max
).
print(MathAddons.min({0, -0}))
print(MathAddons.min({-0, 0}))
prints 0
and -0
rather than -0
and -0
. Was this intentional?
MathAddons.mode
actually returns a string
print(type(MathAddons.mode({ 1 })[1]))
even though the documentation stated that the function returns tables of numbers (IEEE).
I don’t think formatting belongs in math. I don’t recommend parsing formatted string (inverse format strings) as formatting is supposed to display numbers and parsing numbers that’s only supposed to show in the UI feels weird to me. What’s your motivation of the parsing functions - fromComma
, fromKMBT
, fromNumeral
, etc?
The semantics is also an issue.
toKMBT
return a number
for values below ±1000 yet in the docs it’s stated that it returns a string
?
print(MathAddons.toKMBT(1) == 1)
prints true
. This is a serious bug in my opinion, as using string methods could error saying attempting to index number value.
toComma
disregards signed zeroes.
ToFraction
also prints 2^-1022
incorrectly as 1/20001 false
, and did not simplify the denominator of 2^53
when finite IEEE 754 binary64 values is a subset rational with the denominator of 2^k.
print(Math.ToFraction(2 ^ -1022))
print(Math.ToFraction(2 ^ 53))
the first is not even a close approximation, and in the second, the denominator could be simplified to 9007199254740992/1
.
Can I ask what’s the point of MathAddons.pi
when math.pi
already exists? Adding more digits doesn’t make it any more precise:
MathFunctions.pi = 3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555
as math.pi
is 0x1.921fb54442d18p1
which is represented in IEEE 754 binary64 as 0 10000000000 1001001000011111101101010100010001000010110100011000
and at a VM-level the number
data type in Luau is IEEE 754 binary64 in Roblox.
I noticed that you used pairs
on tables with only ordinal indices, do note that as pairs
has the same behaviour as next
, the order of pairs
and next
is explicitly undefined. You should use ipairs
or generalized iteration instead.
I think semantics of many (or majority) of these is something you should improve in your library.
Thanks for the feedback,
Not necessarily intentional but not a bug either, normal math functions like math.min
and math.max
behave the same way,
print(math.min(0,-0)) -- = 0
print(math.min(-0,0)) -- = -0
print(math.max(0,-0)) -- = 0
print(math.max(-0,0)) -- = -0
this is just how table.sort functions, having -0
deemed greater than 0
is not an actual problem, since when being compared to non 0 numbers, they will function normally since -0
is equal to 0
, and order wont matter.
This was my mistake! I forget that although you can still do and inequalities on numbers in forms of strings, that they wouldn’t remain strings. This will be patched in the next update.
These functions are more applicable compared to other functions, although they perform no actual manipulation or computation of the input, there still is math behind it.
This also will be fixed in the next update.
The module runs a loop which plays a game of hot or cold to guess the fraction, it runs a loop of 20,000 times to get the best approximation possible. for numbers less than 1/20001
I have fixed this however, now the function will scale the input so it becomes larger than 1/20001
, this is what the new values now are
print(Math.ToFraction(2 ^ -1022)) -- = 174619484/7.84780619e315
print(Math.ToFraction(2 ^ 53)) -- = 9007199254740992/1
I’m not sure why you would need the first one in any case since any number with over 308 digits is just considered math.huge,
print(1/math.huge) -- = 0
You make a point, this will be removed in the coming update
This doesn’t make any real difference in the code, however this does seem safer to use in case something does get sorted incorrectly.
I appreciate the criticism, most of your suggestions will be implemented in the next update.
Update 4 - Minor Changes
Saturday, July 9th, 2022
- The mode function now returns a table of numbers, instead of strings
- Most formatting functions now return string outputs when
-1000 < x < 1000
- Fraction function now supports numbers smaller than
1/20001
- Solver function now supports being set equal to two functions
f(x) = g(x), solve for x
- Pi -
math.pi
Small personal update regarding the module, yesterday my pc overheated (from Roblox haha) and is refusing to turn on. I may have to buy a new one if the circumstances don’t change, which may take a while considering my budget and specifications I need.
To sum it up the next update for the module is probably in september.
(typing from my phone so disregard the organization)
This is an amazing module, still wondering. Has it been updated and/or are you still maintaining it?
sorry for bump
thanks, and it isnt dead! there will be a few more functions coming out like prime factorization, logical operations like xor, nCr, and others things which are only good for mathematical use.
Im still here taking suggestions just i dont have the same time as i did in the summer when i was out of school
Update 5 - Complex Number Support & Optimizations
Sunday, January 8th, 2023
Statistics and Probability
Factorial/Gamma
Purpose: Returns x!
Parameters:
- Number
Output: Number
Explanation:
- 5! = 120 because 5×4×3×2×1
Example:
local x = module.factorial(5) -- 120
local y = module.factorial(.5) -- 0.8862269254527584
local z = module.factorial(module.Complex.i) -- 0.49801566812031056-0.15494982830241888i
local a = module.factorial(-2.3) -- 3.3283470067886083
-- module.gamma(x) = module.factorial(x-1)
nCr
Purpose: returns the amount of ways to select a group of items where the order of the items does not matter.
Parameters:
-
Amount of items
-
Amount of items being selected
Output: Number
Explanation:
- The formula for nCr is n!/(r!×(n-r)!).
Example:
local x = module.nCr(5,3) -- 10
local y = module.nCr(12,4) -- 495
nPr
Purpose: returns the amount of ways to select a group of items where the order of the items does matter.
Parameters:
-
Amount of items
-
Amount of items being selected
Output: Number
Explanation:
- The formula for nPr is n!/(n-r)!.
Example:
local x = module.nPr(5,3) -- 60
local y = module.nPr(12,4) -- 11880
Pascals Triangle
Purpose: Returns a given row of the pascals triangle
Parameters:
- Row
Output: Number
Explanation:
- Pascals triangle is generated by adding two numbers on the top row and bringing it down a row, for example row with 1 2 1; 0+1 = 1, 1+2 = 3, 2+1 = 3, 1+0 = 1. So 1 3 3 1 becomes the next row
Example:
local x = module.pascalstri(5) -- {1, 5, 10, 10, 5, 1}
local y = module.pascalstri(3) -- {1, 3, 3, 1}
Formatting
Prime Factorization
Purpose: Get the prime factorization of a given input
Parameters:
- Number
Output: String
Explanation:
- For example 12 has a prime factorization of 2^2×3^1, since the bases are prime and this expression equals 12
Example:
local x = module.primeFactor(144) -- x = {{3,2},{2,4}} (this is saying 3^2×2^4 = 144
local y = module.toPercent(97) -- y = {{97,1}}
local z = module.toPercent(13*11) -- z = {{13,1},{11,1}}
Algebra
Lambert W function - Branch 0
Purpose: find the value of x for an equation in the form of x*e^x when its equal to some number
Parameters:
- Number - y
Output: Table
Explanation:
- nope
Lambert W function - Wikipedia
Example:
local x = module.lambert_w0(5*math.exp(5)) -- x = 5
local y = module.lambert_w0(3*math.exp(3)) -- y = 3
local z = module.lambert_w0(2) -- z = 0.8526055020137
local a = module.lambert_w0(module.Complex.i) -- a = 0.37469902073711625+0.5764127230314329i
local b = module.lambert_w0(-.25) -- b = -0.3574029561813889
Lambert W function - Branch -1
Purpose: find the value of x for an equation in the form of x*e^x when its equal to some number
Parameters:
- Number - y
Output: Table
Range: -1/e to 0
Explanation:
- nope
Lambert W function - Wikipedia
Example:
local x = module.lambert_wm1(5*math.exp(5)) -- x =
local y = module.lambert_wm1(3*math.exp(3)) -- y =
local z = module.lambert_wm1(2) -- z =
local a = module.lambert_wm1(module.Complex.i) -- a =
local b = module.lambert_wm1(-.25) -- b = -2.15329236411035
Constants
- G
- g
Complex Numbers
- Absolute Value (abs)
- Min (abs)
- Max (abs)
More normal functions now can accept inputs and outputs of complex numbers
- Nth Lucas Number (lucas)
- Integral (integral)
- Limit (limit)
- Derivative (derivative)
- Average (avg)
- Lambert W branch 0 (lambert_w0)
- Now, you can use i as if its a number, to call it, you can do:
local i = module.Complex.i
print(i^2) -- -1
Goodbye tau, nobody misses you
- Tau, its literally 2*pi
- Old Lambert W function, way too slow
- Old integral function, also too slow
Module will recieve minor updates without announcements.
Please suggest functions you would like added!!
ps: thanks to this GitHub - protobi/lambertw: Javascript implementation of Lambert W function had to rewrite the code in lua, and then implement complex support, but i wouldnt have been able without this post
You should really specify the cost of some of these functions. Using a Riemann Sum for the integral function is going to be extremely costly.
This is a useful library.
Have you considered publishing it on GitHub and allowing contributions like the previous version of it?
I have, although I’m not all that familiar with github so I’m not sure if I’ve made a repo to the best of my abilities
I’ve thrown one together here if you’d like one anyway