Maths formula for the maths guru's

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
User avatar
zorg
Party member
Posts: 3435
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

Re: Maths formula for the maths guru's

Post by zorg »

milon wrote: Thu Jul 22, 2021 1:57 pm
zorg wrote: Wed Jul 21, 2021 6:01 pm The wanted curve looks like two sinusoidal curves, connected at the x = 60% point. it could probably be implemented by using such easing functions and adjusting the range and domain of them (scaling the input & output).
I'm curious what you're getting at, Zorg. Are you talking about 2 separate sin (or cos) curves and using an if/else scenario to decide which to use? Or do you have a meaningful way to combine them into 1 function? I'd love to see the algorithm you're thinking of. (And I'm pretty sure we're also way beyond what togFox looking for, haha! :3 )
Yep, here, should be close: (pub.dom./CC0)

Code: Select all

-- From easings.net
local function easeinsine(x)
	return 1 - math.cos((x * math.pi) / 2)
end
-- From easings.net
local function easeoutsine(x)
	return math.sin((x * math.pi) / 2)
end
-- We want easing in to happen on this range & domain: [0,0.6)->[0,0.6)
-- We want easing out to happen on this range & domain: [0.6,1.0]->[0.6,1.0]
local function trythis(x)
	return x < 0.6 and easeinsine(x/0.6)*0.6 or 0.6+easeoutsine((x-0.6)/0.4)*0.4
end
Me and my stuff :3True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.
User avatar
darkfrei
Party member
Posts: 1168
Joined: Sat Feb 08, 2020 11:09 pm

Re: Maths formula for the maths guru's

Post by darkfrei »

zorg wrote: Thu Jul 22, 2021 6:51 pm
milon wrote: Thu Jul 22, 2021 1:57 pm
zorg wrote: Wed Jul 21, 2021 6:01 pm The wanted curve looks like two sinusoidal curves, connected at the x = 60% point. it could probably be implemented by using such easing functions and adjusting the range and domain of them (scaling the input & output).
I'm curious what you're getting at, Zorg. Are you talking about 2 separate sin (or cos) curves and using an if/else scenario to decide which to use? Or do you have a meaningful way to combine them into 1 function? I'd love to see the algorithm you're thinking of. (And I'm pretty sure we're also way beyond what togFox looking for, haha! :3 )
Yep, here, should be close: (pub.dom./CC0)

Code: Select all

-- From easings.net
local function easeinsine(x)
	return 1 - math.cos((x * math.pi) / 2)
end
-- From easings.net
local function easeoutsine(x)
	return math.sin((x * math.pi) / 2)
end
-- We want easing in to happen on this range & domain: [0,0.6)->[0,0.6)
-- We want easing out to happen on this range & domain: [0.6,1.0]->[0.6,1.0]
local function trythis(x)
	return x < 0.6 and easeinsine(x/0.6)*0.6 or 0.6+easeoutsine((x-0.6)/0.4)*0.4
end
Looks nice!

https://www.desmos.com/calculator/rbhrgbkc1l

(together)

What if the x0 is not same as y0?
Attachments
2021-07-22T22_15_15-Desmos _ Grafik-Rechner.png
2021-07-22T22_15_15-Desmos _ Grafik-Rechner.png (74.62 KiB) Viewed 6550 times
:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
User avatar
pgimeno
Party member
Posts: 3541
Joined: Sun Oct 18, 2015 2:58 pm

Re: Maths formula for the maths guru's

Post by pgimeno »

togFox wrote: Wed Jul 21, 2021 4:55 am The formula you see is the MS Excel trend line (ignore the error - I couldn't remove that one) but it really means nothing to me.
Why not?

Code: Select all

local function payout(x)
  return -3e-6*x^4+0.0003*x^3+0.0107*x^2-0.0669*x+0.4196
end

print(payout(0)) -- 0.4196
print(payout(10)) -- 1.0906
print(payout(20)) -- 5.2816
print(payout(30)) -- 13.7126
print(payout(40)) -- 26.3836
print(payout(50)) -- 42.5746
print(payout(60)) -- 60.8456
print(payout(70)) -- 79.0366
print(payout(80)) -- 94.2676
print(payout(90)) -- 102.9386
print(payout(100)) -- 100.7296
The problem is that it's just an approximate fit of degree 4, so it's not exact; it goes over 100 at some points, but it's what can be done fitting the given points to a 4th degree polynomial. To exactly pass through all the points, you would need a polynomial of a bigger order, up to 10.

By relaxing the constraint that the curve must approximate the points but preserving your other constraints, a 4th degree curve will do.

To keep things simple, let's normalize to 0..1 and apply the factor of 100 later.

You want a polynomial for which:

1. y = 0 when x = 0
2. y = 1 when x = 1
3. y = 0.65 when x = 0.65
4. The derivative at 0 is 0 (so it starts horizontal)
5. The derivative at 1 is 0 (so it ends horizontal)

That's five constraints, meaning we need a quartic, because all constraints are independent. Two of the constraints give immediate values for the terms of degrees 0 and 1: they must both be zero because of constraints 1 and 4. So we're after a, b and c for this curve:

y = a*x^4+b*x^3+c*x^2

where:

a + b + c = 1 (per constraint 2)
a*0.17850625 + b*0.274625 + c*0.4225 = 0.65 (per constraint 3)
4*a + 3*b + 2*c = 0 (per constraint 5)

*fires Derive*

Solution: a = -120/91, b = 58/91, c = 153/91

So:

Code: Select all

local function payout(x)
  return ((-120/91*x+58/91)*x+153/91)*x*x
end

print(payout(0/100)*100) -- 0
print(payout(10/100)*100) -- 1.7318681318681
print(payout(20/100)*100) -- 7.0241758241758
print(payout(30/100)*100) -- 15.784615384615
print(payout(40/100)*100) -- 27.604395604396
print(payout(50/100)*100) -- 41.758241758242
print(payout(60/100)*100) -- 57.204395604396
print(payout(65/100)*100) -- 65
print(payout(70/100)*100) -- 72.584615384615
print(payout(80/100)*100) -- 86.224175824176
print(payout(90/100)*100) -- 96.131868131868
print(payout(100/100)*100) -- 100
That's four multiplications, two sums... and zero trigonometric functions :nyu:

Changing the threshold to 2/3 = 0.666666... instead of 0.65, the solution is even simpler: a = -1.5, b = 1, c = 1.5, which gives the following:

Code: Select all

local function payout(x)
  return ((-1.5*x+1)*x+1.5)*x*x
end

print(payout(0/100)*100) -- 0
print(payout(10/100)*100) -- 1.585
print(payout(20/100)*100) -- 6.56
print(payout(30/100)*100) -- 14.985
print(payout(40/100)*100) -- 26.56
print(payout(50/100)*100) -- 40.625
print(payout(60/100)*100) -- 56.16
print(payout(66.6666/100)*100) -- 66.666562962941
print(payout(70/100)*100) -- 71.785
print(payout(80/100)*100) -- 85.76
print(payout(90/100)*100) -- 95.985
print(payout(100/100)*100) -- 100
Edit: Pics, or it didn't happen.
Attachments
payout.png
payout.png (21.83 KiB) Viewed 6536 times
Last edited by pgimeno on Thu Jul 22, 2021 10:16 pm, edited 1 time in total.
User avatar
togFox
Party member
Posts: 764
Joined: Sat Jan 30, 2021 9:46 am
Location: Brisbane, Oztralia

Re: Maths formula for the maths guru's

Post by togFox »

This has turned into a great thread. I love seeing all the different technical approaches.

I understood about half of what pgimeno said in my first read so will read that again when I'm not on the bus.
Current project:
https://togfox.itch.io/backyard-gridiron-manager
American football manager/sim game - build and manage a roster and win season after season
User avatar
pgimeno
Party member
Posts: 3541
Joined: Sun Oct 18, 2015 2:58 pm

Re: Maths formula for the maths guru's

Post by pgimeno »

In case you want to change the payoff point later, I've extracted the formulas to calculate a, b, c for a given payoff p between 0 and 1:

Code: Select all

a = (2*p-1)/(p*(p-1))
b = -2*(p*p+p-1)/(p*(p-1))
c = (3*p*p-p-1)/(p*(p-1))
You already have the values for p=0.65 and p=0.666666...; now you can find them for any given payoff.
User avatar
darkfrei
Party member
Posts: 1168
Joined: Sat Feb 08, 2020 11:09 pm

Re: Maths formula for the maths guru's

Post by darkfrei »

pgimeno wrote: Thu Jul 22, 2021 11:14 pm In case you want to change the payoff point later, I've extracted the formulas to calculate a, b, c for a given payoff p between 0 and 1:

Code: Select all

a = (2*p-1)/(p*(p-1))
b = -2*(p*p+p-1)/(p*(p-1))
c = (3*p*p-p-1)/(p*(p-1))
You already have the values for p=0.65 and p=0.666666...; now you can find them for any given payoff.
Sometimes the result is not trivial:
https://www.desmos.com/calculator/4dcn9br42p
Attachments
2021-07-23T09_29_55-Desmos _ Grafik-Rechner.png
2021-07-23T09_29_55-Desmos _ Grafik-Rechner.png (140.43 KiB) Viewed 6481 times
:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
User avatar
pgimeno
Party member
Posts: 3541
Joined: Sun Oct 18, 2015 2:58 pm

Re: Maths formula for the maths guru's

Post by pgimeno »

Yeah, these are limitations of using a 4th degree polynomial. Setting the second derivative to 0 at x=0 gives us the value of p at which this happens, namely (sqrt(13)+1)/6 which is a little under 0.7676. Similarly, for p < (11-sqrt(65))/14 (a little under 0.21) you can get values above 1 on the other end. Therefore, this is valid for p between 0.21 and 0.7675.

Edit: Oops, I made a blunder. The correct minimum value is the symmetrical of that one, i.e. (5-sqrt(13))/6, which is a little above 0.2324. So the formulas are valid for p between 0.2325 and 0.7675.
User avatar
darkfrei
Party member
Posts: 1168
Joined: Sat Feb 08, 2020 11:09 pm

Re: Maths formula for the maths guru's

Post by darkfrei »

How about a not trivial situation, where the point is at the x = 0.7 and y = 0.6?
Native solution:
a=-4.2
b=6.4
c=-1.2
f(0.7) = 0.59878

1. y = 0 when x = 0
2. y = 1 when x = 1
3. y = 0.6 when x = 0.7
4. The derivative at 0 is 0 (so it starts horizontal)
5. The derivative at 1 is 0 (so it ends horizontal)
Attachments
2021-07-23-Excel.png
2021-07-23-Excel.png (29.31 KiB) Viewed 6438 times
:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
User avatar
pgimeno
Party member
Posts: 3541
Joined: Sun Oct 18, 2015 2:58 pm

Re: Maths formula for the maths guru's

Post by pgimeno »

darkfrei wrote: Fri Jul 23, 2021 3:34 pm How about a not trivial situation, where the point is at the x = 0.7 and y = 0.6?
That gives me a = -1840/441, b = 2798/441 and c = -517/441. The point where y = x can be calculated by solving for p in the formulas for a, b and c; it is (479+sqrt(1040881))/1840, which is approx. 0.814802041885. Since it is well out of the range 0.2325..0.7675, it yields negative values for some inputs. You'd need a higher degree polynomial to avoid that.
User avatar
pgimeno
Party member
Posts: 3541
Joined: Sun Oct 18, 2015 2:58 pm

Re: Maths formula for the maths guru's

Post by pgimeno »

Just for fun, I've adjusted the points given by togFox to a 10th-degree polynomial (that's the minimal degree necessary when given 11 arbitrary points as in this case). The result has some nasty surprises, in the first two segments and the last segment:
10-degree.png
10-degree.png (17.15 KiB) Viewed 6349 times
It appears that the changes in curvature forced by the placement of the points don't go well with a polynomial approximation. So, depending on how important it is to cross the given points, I'd go with piecewise interpolation. Refreezed already showed piecewise linear interpolation; it's also possible to use piecewise cubic interpolation to give a smooth look.
Post Reply

Who is online

Users browsing this forum: No registered users and 13 guests