decimals not working with factorials in roblox lua - lua

What do you want to achieve?
I want to make a factorial function
What is the issue?
I can't find any way to solve factorials unless they are whole numbers
What solutions have you tried so far?
I have looked on roblox devforum and youtube and google and discord and I literally can't find any way to get decimals to properly work with factorials
the only thing I know is that you can use gamma functions to solve decimal factorials but I am looking and I have no idea how I would implement that into luau so I am really struggling
I even used Stirling's approximation but that is not 100% true as I need something to be completely true to the actual answer
local function SolveFactorial(FN)
if string.match(FN, "^-") then
local T = 1
FN *= -1
for i = FN, 1, -1 do
T = T * i
end
T *= -1
return T
else
local T = 1
for i = FN, 1, -1 do
T = T * i
end
return T
end
end
this is a normal factorial function that works with all integers expect 0
local function SF(FN)
if string.match(FN, "^-") then
FN *= -1
local N = math.sqrt(2*math.pi*FN)*math.pow((FN/math.exp(1)), FN)
N *= -1
return N
else
local N = math.sqrt(2*math.pi*FN)*math.pow((FN/math.exp(1)), FN)
return N
end
end
and this is Stirling's approximation which as I said before isn't 100% accurate
these are the two functions that I have so far and I don't know what I should do at this point to fix it
is there a way to use the gamma function or is there an easier way to do this then what I am doing atm
note that this is roblox lua!!!
any help will really save a lot of time thank you, nici

Your question title is a little misleading, it's not that decimals aren't working. It's that Stirling's Approximation provides inaccurate numbers for your purposes.
If you need a gamma function, there's an implementation on Rosetta Code that's pretty easy to use. I've made small adjustments and transcribed it here :
local function gammafunc(z)
local gamma = 0.577215664901
local coeff = -0.65587807152056
local quad = -0.042002635033944
local qui = 0.16653861138228
local set = -0.042197734555571
function recigamma(rz)
return rz + gamma * rz^2 + coeff * rz^3 + quad * rz^4 + qui * rz^5 + set * rz^6
end
if z == 1 then
return 1
elseif math.abs(z) <= 0.5 then
return 1 / recigamma(z)
else
return (z - 1) * gammafunc(z - 1)
end
end
In order to get it to properly return the correct factorial values, you need to offset z by 1.
for n = 0.0, 10, 0.2 do
local f1 = factorial(n)
local f2 = stirlingApprox(n)
local f3 = gammafunc(n + 1)
print(n, f1, f2, f3)
end
---[[ Returns...
n n! Stirling Gamma
0.0 1.0000 -0.0000 1.0000
0.2 0.6652 0.9182
0.4 0.7366 0.8872
0.6 0.7843 0.8934
0.8 0.8427 0.9314
1.0 1.0000 0.9221 1.0000
1.2 1.0293 1.1018
1.4 1.1714 1.2421
1.6 1.3579 1.4295
1.8 1.6014 1.6765
2.0 2.0000 1.9190 2.0000
2.2 2.3344 2.4240
2.4 2.8800 2.9811
2.6 3.6003 3.7167
2.8 4.5571 4.6942
3.0 6.0000 5.8362 6.0000
3.2 7.5579 7.7567
3.4 9.8914 10.1358
3.6 13.0759 13.3803
3.8 17.4518 17.8378
4.0 24.0000 23.5062 24.0000
4.2 31.9393 32.5781
4.4 43.7635 44.5977
4.6 60.4506 61.5492
4.8 84.1502 85.6217
5.0 120.0000 118.0192 120.0000
5.2 166.7162 169.4060
5.4 237.1499 240.8277
5.6 339.6157 344.6753
5.8 489.5289 496.6057
6.0 720.0000 710.0782 720.0000
6.2 1036.3071 1050.3173
6.4 1521.4128 1541.2974
6.6 2246.5097 2274.8568
6.8 3335.8193 3376.9185
7.0 5040.0000 4980.3958 5040.0000
7.2 7475.3217 7562.2846
7.4 11278.2406 11405.6005
7.6 17101.8057 17288.9114
7.8 26060.2260 26339.9645
8.0 40320.0000 39902.3955 40320.0000
8.2 61384.0725 62010.7339
8.4 94864.1090 95807.0442
8.6 147262.8822 148684.6384
8.8 229608.1738 231791.6880
9.0 362880.0000 359536.8728 362880.0000
9.2 565356.8075 570498.7521
9.4 892663.0429 900586.2158
9.6 1415149.6282 1427372.5285
9.8 2252332.9545 2271558.5427
10.0 3628800.0000 3598695.6187 3628800.0000]]
Please keep in mind that this implementation runs the same stackoverflow risk that the traditional factorial function has with larger numbers as it needs to recursively calculate values. The Stirling approximation that you're using is significantly faster and that might be good enough in some cases.

Related

How to generate a random decimal number in love2D?

I tried generating a random decimal number between (lets say between 0.3 and 0.8) in love2d using the following code:
x=math.random(0.3, 0.8)
print(x)
but what happens is it generates 0.3 every single time I run the program and the 0 in 0.4 kind of flickers (in the sense like it changes to 1).
If it helps, here's a screen record of what happens https://vimeo.com/632949687
Your problem is underspecified. Here are two simple solutions; they're not equivalent.
This generates random numbers in the set {0.3,0.4,0.5,0.6,0.7,0.8}:
math.random(3,8)/10
This generates random numbers in the interval [0.3,0.8):
0.3+(0.8-0.3)*math.random()
In LÖVE there is a platform independent version of random() present.
https://love2d.org/wiki/love.math.random
With no need to use of math.randomseed() or love.math.setRandomSeed().
For float numbers in the range 0 and 1 simply use...
love.math.random()
'but what happens is it generates 0.3 every single time'
Same here, so the simpliest way seems to be #lhf' example.
check the function
function random(min, max, precision)
local precision = precision or 0
local num = math.random()
local range = math.abs(max - min)
local offset = range * num
local randomnum = min + offset
return math.floor(randomnum * math.pow(10, precision) + 0.5) / math.pow(10, precision)
end

Rails / Ruby how to always show decimal precision

I am currently converting some python statistics library that needs to produce a number with high decimal precision. For example, I did this:
i = 1
n = 151
sum = (i - 3/8) / (n + 1/4)
it will result to 0.
My question is how to always show decimal precision automatically when I do this kind of computation?
My desired output is:
0.004132231404958678
In ruby all the arithmetic operations result in the value of the same type as operands (the one having better precision.)
That said, 3/4 is an integer division, resulting in 0.
To make your example working, you are to ensure you are not losing precision anywhere:
i = 1.0
n = 151.0
sum = (i - 3.0/8) / (n + 1/4.0)
Please note, that as in most (if not all) languages, Float is tainted:
0.1 + 0.2 #⇒ 0.30000000000000004
If you need an exact value, you might use BigDecimal or Rational.

lua decimals break around -0.1 to 0.1 (exclusive)

I have a Lua for loop that iterates through numbers from -1 to 1 by increments of 0.01, and is producing numbers as bad as 6.6613381477509e-016 in the range of -0.1 to 0.1 (exclusive)
I am using Lua in the LOVE engine (v 0.9.2), written in C++
I would much rather solve the problem than just receive an info dump of an explanation, but I'd rather that than nothing at all.
(also I do understand the general reason floats are inaccurate, so that may be left out of explanations)
You've already known the reason, here's a possible solution: don't loop with floating point numbers, use integers.
Instead of
for i = -1, 1, 0.01 do
use:
for i = -100, 100 do
print(i / 100)
end

Erlang Calculating Pi to X decimal places

I have been given this question to work on a solution. I'm struggling to get my head around the recursion. Some break down of the question would be very helpful.
Given that Pi can be estimated using the function 4 * (1 – 1/3 + 1/5 – 1/7 + …) with more terms giving greater accuracy, write a function that calculates Pi to an accuracy of 5 decimal places.
I have got some example code however I really don't understand where/why the variables are entered like this. Possible breakdown of this code and why it is not accurate would be appreciated.
-module (pi).
-export ([pi/0]).
pi() -> 4 * pi(0,1,1).
pi(T,M,D) ->
A = 1 / D,
if
A > 0.00001 -> pi(T+(M*A), M*-1, D+2);
true -> T
end.
The formula comes from the evaluation of tg(pi/4) which is equal to 1. The inverse:
pi/4 = arctg(1)
so
pi = 4* arctg(1).
using the technique of the Taylor series:
arctg (x) = x - x^3/3 + ... + (-1)^n x^(2n+1)/(2n+1) + o(x^(2n+1))
so when x = 1 you get your formula:
pi = 4 * (1 – 1/3 + 1/5 – 1/7 + …)
the problem is to find an approximation of pi with an accuracy of 0.00001 (5 decimal). Lookinq at the formula, you can notice that
at each step (1/3, 1/5,...) the new term to add:
is smaller than the previous one,
has the opposite sign.
This means that each term is an upper estimation of the error (the term o(x^(2n+1))) between the real value of pi and the evaluation up to this term.
So it can be use to stop the recursion at a level where it is guaranty that the approximation is better than this term. To be correct, the program
you propose multiply the final result of the recursion by 4, so the error is no more guaranteed to be smaller than term.
looking at the code:
pi() -> 4 * pi(0,1,1).
% T = 0 is the initial estimation
% M = 1 is the sign
% D = 1 initial value of the term's index in the Taylor serie
pi(T,M,D) ->
A = 1 / D,
% evaluate the term value
if
A > 0.00001 -> pi(T+(M*A), M*-1, D+2);
% if the precision is not reach call the pi function with,
% new serie's evaluation (the previous one + sign * term): T+(M*A)
% new inverted sign: M*-1
% new index: D+2
true -> T
% if the precision is reached, give the result T
end.
To be sure that you have reached the right accuracy, I propose to replace A > 0.00001 by A > 0.0000025 (= 0.00001/4)
I can't find any error in this code, but I can't test it right now, anyway:
T is probably "total", M is "multiplicator", and D is "divisor".
By every step you:
check (the 'if' is in some way similar to a switch/case in c/c++/java) if the next term (A = 1/D) is bigger than 0.00001. If not, you can stop the recursion, you've got the 5 decimal places you were looking for. So "if true (default case) -> return T"
if it's bigger, you multiply A by M, add to the total, then multiply M by -1, add 2 to D, and repeat (so you get the next term, add again, and so on).
pi(T,M,D) ->
A = 1 / D,
if
A > 0.00001 -> pi(T+(M*A), M*-1, D+2);
true -> T
end.
I don't know Erlang myself but from the looks of it you are checking if 1/D is < 0.00001 when in reality you should be checking 4 * 1/D because that 4 is going to be multiplied through. For example in your case if 1/D was 0.000003 you would stop four function, but your total would actually have changed by 0.000012. Hope this helps.

Math.random on non whole numbers

How can I generate numbers that are less than 1?
for example i would like to generate numbers from 0.1 to 0.9
what I've tried:
math.random(0.1,0.9)
Lua's math.random() with two arguments returns an integer within the specified range.
When called with no arguments, it returns a pseudo-random real number in between 0.0 and 1.0.
To get real numbers in a specified range, you need to do your own scaling; for example:
math.random() * 0.8 + 0.1
will give you a random real number between 0.1 and 0.9. More generally:
math.random() * (hi - lo) + lo
which you can wrap in your own function if you like.
But I'll note that that's a fairly peculiar range. If you really want a random number selected from 0.1, 0.2, 0.3, 0.4, ..., 0.9, then you should generate an integer in the range 1 to 9 and then divide it by 10.0:
math.random(1, 9) / 10.0
Keep in mind that most real numbers cannot be represented exactly in floating-point.
You can use math.random() (no args) to generate a number between 0 and 1, and use that to blend between your two target numbers.
-- generates a random real number between a (inclusive) and b (exclusive)
function rand_real(a, b)
return a + (b - a) * math.random()
end
(math.random(10,90)) / 100
This generates a number from 10 to 90 and the division gives you a number from 0.1 to 0.9.

Resources