How to bounce a number within a range? - math

I'd like to request help in form of pseudo-code for bouncing or "ping-ponging" a number in a range, by which I mean adding a number to another value in a range, where that number instead of exceeding the range or being clamped to it, is continuously bounced back into it.
Example
Consider the following variables:
Range: (-2, 2)
Starting value in the range: 1
Added value: 14
The number would start at 1 and go through 14 alterations, as following:
2
1
0
-1
-2
-1
0
1
2
1
0
-1
-2
-1
The code I am trying to write would only return the final number of this sequence, which is -1.
Specifications
— The code must not use a while loop.
— The code must be able to work with non-integer values.
— The code must be efficient and fail-proof.
Thank you in advance.

Just have a for loop that goes for the number of steps specified.
Inside the loop add to a running total the value of each step using a variable to hold the step value, and when you hit the limit multiply the step value by -1 to get it going in the other direction.
For the number of steps required
Add value to total
If total exceeds upper limit
Value *= -1
If value is less than lower limit
Value *= -1
Return the total when the loop ends
Edit: I'm on my phone and psedocode bit formatting got borked

First, compute cycle = 2 * (max - min) and find the largest integer n such that cycle * n is less than or equal to added value. One way to do this is to calculate full cycles = round_toward_zero(added value / cycle). We can immediately subtract from added value the value cycle * full cycles because moving by cycle returns you to where you started and headed in the same direction, so we only need to consider the portion of added value that is strictly greater than an even multiple of cycle. Let us define modified value = added value - cycle * full cycles.
Next, calculate position = starting position + modified value. Given that min <= starting position <= max, there are three cases for position:
position < min. In this case, modified value must have been negative, so we can simply "bounce right" by calculating position' = min + (min - position). There are two sub-cases now:
min <= position' <= max: simply return position' as the answer
max < position': we must "bounce back" again by calculating position'' = max - (position' - max). This time, position'' is guaranteed to be between min and max since modified value is guaranteed to to be between -2 * (max - min) and 0... so just return position''.
min <= position <= max. In this case, no additional bouncing is required, so just return position.
position > max. In this case, modified value must have been positive, so we can simply "bounce left" by calculating position' = max - (position - max). There are two sub-cases now:
position' < min: we must "bounce back" again by calculating position'' = min + (min - position'). This time, position'' is guaranteed to be between min and max since modified value is guaranteed to be between 0 and 2 * (max - min)... so just return position''.
min <= position' <= max: simply return position' as the answer
Example:
Range: (-2, 2)
Starting value in the range: 1
Added value: 14
min = -2
max = 2
starting position = 1
added value = 14
cycle = 2 * (max - min) = 2 * 4 = 8
full cycles = round_toward_zero(added value / cycle)
= round_toward_zero(14 / 8)
= round_toward_zero(1.75)
= 1
modified value = added value - cycle * full cycles
= 14 - 8 * 1
= 6
position = starting position + modified value
= 1 + 6
= 7
position = 7 > 2 = max
position' = max - (position - max)
= 2 - (7 - 2)
= 2 - 5
= -3
position' = -3 < -2 = min
position'' = min + (min - position')
= -2 + (-2 - -3)
= -2 + 1
= -1
Now, this might seem like a lot of calculations. For small numbers of steps, it might be faster just to do a loop. However, for large added values, this approach is significantly better.

Related

Lua: How do I calculate a random number between 50 and 500, with an average result of 100?

I think this is a log-normal distribution? I'm not sure. The lua I have is here:
local min = 50
local max = 500
local avg = 100
local fFloat = ( RandomInt( 0, avg ) / 100 ) ^ 2 -- float between 0 and 1, squared
local iRange = max - min -- range of min-max
local fDistribution = ( ( fFloat * iRange ) + min ) / 100
finalRandPerc = fDistribution * RandomInt( min, max ) / 100
It is close to working, but sometimes generates numbers that are slightly too large.
This can be done in literally infinite number of ways. One other approach is to generate a number from binomial distribution, multiply with 450 and add 50. I will leave the task of finding the right parameters for the binomial distribution to you.
How do I calculate a random number between 50 and 500, with an average result of 100?
You can use Chi-squared of degree 4 with its tail removed.
It is very easy to calculate.
local function random_50_500()
-- result is from 50 to 500
-- mean is very near to 100
local x
repeat
x = math.log(math.random()) + math.log(math.random())
until x > -18
return x * -25 + 50
end

Number of action per year. Combinatorics question

I'm writing a diploma about vaccines. There is a region, its population and 12 month. There is an array of 12 values from 0 to 1 with step 0.01. It means which part of population should we vaccinate in every month.
For example if we have array = [0.1,0,0,0,0,0,0,0,0,0,0,0]. That means that we should vaccinate 0.1 of region population only in first month.
Another array = [0, 0.23,0,0,0,0,0,0, 0.02,0,0,0]. It means that we should vaccinate 0.23 of region population in second month and 0.02 of region population in 9th month.
So the question is: how to generate (using 3 loops) 12(months) * 12(times of vaccinating) * 100 (number of steps from 0 to 1) = 14_400 number of arrays that will contain every version of these combinations.
For now I have this code:
for(int month = 0;month<12;month++){
for (double step = 0;step<=1;step+=0.01){
double[] arr = new double[12];
arr[month] = step;
}
}
I need to add 3d loop that will vary number of vaccinating per year.
Have no idea how to write it.
Idk if it is understandable.
Hope u get it otherwise ask me, please.
You have 101 variants for the first month 0.00, 0.01..1.00
And 101 variants for the second month - same values.
And 101*101 possible combinations for two months.
Continuing - for all 12 months you have 101^12 variants ~ 10^24
It is not possible to generate and store so many combinations (at least in the current decade)
If step is larger than 0.01, then combination count might be reliable. General formula is P=N^M where N is number of variants per month, M is number of months
You can traverse all combinations representing all integers in range 0..P-1 in N-ric numeral system. Or make digit counter:
fill array D[12] with zeros
repeat
increment element at the last index by step value
if it reaches the limit, make it zero
and increment element at the next index
until the first element reaches the limit
It is similar to counting 08, 09, here we cannot increment 9, so make 10 and so on
s = 1
m = 3
mx = 3
l = [0]*m
i = 0
while i < m:
print([x/3 for x in l])
i = 0
l[i] += s
while (i < m) and l[i] > mx:
l[i] = 0
i += 1
if i < m:
l[i] += s
Python code prints 64 ((mx/s+1)^m=4^3) variants like [0.3333, 0.6666, 0.0]

How to find the range for a given number, interval and start value?

Provided the below values
start value = 1
End Value = 20
Interval = 5
I have been provided a number 6. I have to find the range of numbers in which the number 6 falls say now the answer is 6-10.
If the given number is greater than the end value then return the same number.
Is there any formula so that i can generate the range for the number?
UPDATE
I tried the below solution, But it is not working if the range interval is changed,
$end_value = $start_value + $range_interval;
// we blindly return the last term if value is greater than max value
if ($input_num > $end_value) {
return '>' . $end_value;
}
// we also find if its a first value
if ($input_num <= $end_value && $value >= $start_value) {
return $start_value . '-' . $end_value;
}
// logic to find the range for a given integer
$dived_value = $input_num/$end_value;
// round the value to get the exact match
$rounded_value = ceil($dived_value);
$upper_bound_range = $rounded_value*$end_value;
$lower_bound_range = $upper_bound_range - $end_value;
return $lower_bound_range . '-'. $upper_bound_range;
In (c-style) pseudocode:
// Integer division assumed
rangeNumber = (yourNumber - startValue) / rangeLength;
lower_bound_range = startValue + rangeNumber*rangeLength;
upper_bound_range = lower_bound_range + rangeLength-1;
For your input:
rangeNumber = (6-1)/5 = 1
lower_bound_range = 1 + 5*1 = 6
upper_bound_range = 10
and so range is [6, 10]
The answer depends on whether you talk about integers or floats. Since all your example numbers are integers, I assume you talk about those. I further assume that all your intervals contain the same number of integers, in your example 5, namely 1...5, 6...10, 11...15, and 16...20. Note that 0 is not contained in the 1st interval (otherwise the 1st interval had 6 numbers).
In this case the answer is easy.
Let be:
s the start value that is not contained in the 1st interval,
i the interval size, i.e. the number of integers that it contains,
p the provided number to which an interval should be assigned,
b the 1st integer in this interval, and
e the last integer in this interval.
Then:
b = s + (p-s-1)\i * i + 1 (here, "\" means integer division, i.e. without remainder)
e = b + i - 1
In your example:
s = 0, i = 5, p = 6, thus
b = 0 + (6-0-1)\5 * 5 + 1 = 6
e = 6 + 5 - 1 = 10

Minimum number of element required to make a sequence that sums to a particular number

Suppose there is number s=12 , now i want to make sequence with the element a1+a2+.....+an=12.
The criteria is as follows-
n must be minimum.
a1 and an must be 1;
ai can differs a(i-1) by only 1,0 and -1.
for s=12 the result is 6.
So how to find the minimum value of n.
Algorithm for finding n from given s:
1.Find q = FLOOR( SQRT(s-1) )
2.Find r = q^2 + q
3.If s <= r then n = 2q, else n = 2q + 1
Example: s = 12
q = FLOOR( SQRT(12-1) ) = FLOOR(SQRT(11) = 3
r = 3^2 + 3 = 12
12 <= 12, therefore n = 2*3 = 6
Example: s = 160
q = FLOOR( SQRT(160-1) ) = FLOOR(SQRT(159) = 12
r = 12^2 + 12 = 156
159 > 156, therefore n = 2*12 + 1 = 25
and the 25-numbers sequence for
159: 1,2,3,4,5,6,7,8,9,10,10,10,9,10,10,10,9,8,7,6,5,4,3,2,1
Here's a way to visualize the solution.
First, draw the smallest triangle (rows containing successful odd numbers of stars) that has a greater or equal number of stars to n. In this case, we draw a 16-star triangle.
*
***
*****
*******
Then we have to remove 16 - 12 = 4 more stars. We do this diagonally starting from the top.
1
**2
****3
******4
The result is:
**
****
******
Finally, add up the column heights to get the final answer:
1, 2, 3, 3, 2, 1.
There are two cases: s odd and s even. When s is odd, you have the sequence:
1, 2, 3, ..., (s-1)/2, (s-1)/2, (s-1)/2-1, (s-1)/2-2, ..., 1
when n is even you have:
1, 2, 3, ..., s/2, s/2-1, s/2-2, ..., 1
The maximum possible for any given series of length n is:
n is even => (n^2+2n)/4
n is odd => (n+1)^2/4
These two results are arrived at easily enough by looking at the simple arithmetic sum of series where in the case of n even it is twice the sum of the series 1...n/2. In the case of n odd it is twice the sum of the series 1...(n-1)/2 and add on n+1/2 (the middle element).
Clearly you can generate any positive number that is less than this max as long as n>3.
So the problem then becomes finding the smallest n with a max greater than your target.
Algorithmically I'd go for:
Find (sqrt(4*s)-1) and round up to the next odd number. Call this M. This is an easy to work out value and will represent the lowest odd n that will work.
Check M-1 to see if its max sum is greater than s. If so then that your n is M-1. Otherwise your n is M.
Thank all you answer me. I derived a simpler solution. The algorithm looks like-
First find what is the maximum sum that can be made using n element-
if n=1 -> 1 sum=1;
if n=2 -> 1,1 sum=2;
if n=3 -> 1,2,1 sum=4;
if n=4 -> 1,2,2,1 sum=6;
if n=5 -> 1,2,3,2,1 sum=9;
if n=6 -> 1,2,3,3,2,1 sum=12;
So from observation it is clear that form any number,n 9<n<=12 can be
made using 6 element, similarly number
6<n<=9 can be made at using 5 element.
So it require only a binary search to find the number of
element that make a particular number.

Math Looping Between Min and Max Using Mod?

i'm attempting to build a tiny (or perhaps not so tiny) formula that will contain numbers between a set min and max, but also loop these numbers so they are not clipped if they are outside of the range. so far, this is what i have.
min1 = 10
max1 = 90
val1 = 92
//will make 11, which is what i want since it loops
formula: min(max(min1,min(val1,max1)),mod(val1,max1)+min1)
however, i'd like it to loop the other direction also, so that if val1 is 5, which is -5 outside of min1, it will become 86.
another problem i'm running into is that
max1 % max1 != max1
as i want it to, since the max is part of the range
trying to be clear, here are some examples of desired output based on a range with looping
min1 = 10
max1 = 90
----------------------------------------------
val1 = 30 //within range: stays as 30
val1 = 90 //within range: stays as 90
val1 = -6 //below range: loops to becomes 75
val1 = 98 //above range: loops to becomes 17
val1 = 91 //above range: loops to becomes 10
i'd like not to resort to using a series of if/else statements, but one would be fine if it's absolutely required. is that even possible?
int loop(int val, int min, int max)
{
int p = max-min+1;
int mod = (val-min)%p;
if(mod<0)
mod += p;
return min+mod;
}
Mathematically, you should be able to do something like this:
((val-min) `mod` (max-min+1)) + min
Move your range down to be zero-based, clip off the high end, and shift it back to the right range. Unfortunately, the % operator in C gives negative results for negative numbers. So:
3 % 10 => 3
13 % 10 => 3
-3 % 10 => -3
-13 % 10 => -3
So to get rid of these negatives, we need one extra modulo:
((val-min)%(max-min+1) + (max-min+1)) % (max-min+1) + min
Sorry. Deleted previous answer. Try this one:
((val-min)%(max-min)+max-min)%(max-min)+min
EDIT: if you want max to be a valid value instead of overflowing to min, replace max by max+1 in all 3 places.

Resources