Math Looping Between Min and Max Using Mod? - math

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.

Related

Is it possible to find a few common multiples of a list of numbers, without them having to be integers?

I don't even know if something like this is possible, but:
Let us say we have three numbers:
A = 6
B = 7.5
C = 24
I would like to find a few evenly spaced common multiples of these numbers between 0 and 2.
So the requirement is: one_of_these_numbers / common_multiple = an_integer (or almost an integer with a particular tolerance)
For example, a good result would be [0.1 , 0.5 , 1 , 1.5]
I have no idea if this is possible, because one can not iterate through a range of floats, but is there a smart way to do it?
I am using python, but a solution could be represented in any language of your preference.
Thank you for your help!
While I was writing my question, I actually came up with an idea for the solution.
To find common divisors using code, we have to work with integers.
My solution is to multiply all numbers by a factor = 1, 10, 100, ...
so that we can act as if they are integers, find their integer common divisors, and then redivide them by the factor to get a result.
Better explained in code:
a = 6
b = 7.5
c = 24
# Find a few possible divisors between 0 and 2 so that all numbers are divisible
by div.
# We define a function that finds all divisors in a range of numbers, supposing
all numbers are integers.
def find_common_divisors(numbers, range_start, range_end):
results = []
for i in range(range_start + 1, range_end + 1):
if all([e % i == 0 for e in numbers]):
results.append(i)
return results
def main():
nums = [a, b, c]
range_start = 0
range_end = 2
factor = 1
results = [1]
while factor < 11:
nums_i = [e * factor for e in nums]
range_end_i = range_end * factor
results += [e / factor for e in find_common_divisors(nums_i, range_start, range_end_i)]
factor *= 10
print(sorted(set(results)))
if __name__ == '__main__':
main()
For these particular numbers, I get the output:
[0.1, 0.3, 0.5, 1, 1.5]
If we need more results, we can adjust while factor < 11: to a higher number than 11 like 101.
I am curious to see if I made any mistake in my code.
Happy to hear some feedback.
Thank you!

How to bounce a number within a range?

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.

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 compute floor(log2(5**x)) without floating point arithmetic or long integer computation

The problem is how do we compute the integer value of floor(log2(5^x)) without floating point arithmetic or long integer computation? I'm looking for a simple, efficient and mathematically elegant way.
Observations:
The formula is just the number of bits in 5**x (plus 1)
Attempts:
I tried to simplify it to:
floor(x*log2(5))
In my use case, x is not extremely large, probably just 1-100. While an elegant formula that works for small values would suffice me, I would be interested in a formula/algorithm that works for any value of x
I'm making a reference software implementation of universal numbers (type III). I want to make everything easily convertible to microcode by purely using bitwise and basic operations. This is one of the formulas i need to simplify.
As you correctly note, log2(5**x) == x * log2(5). log2(5) is a constant, which can be approximated to 2.3219281.
However, floats aren't allowed per the question. Not an issue!
log2_5 = 23219281;
scale = 10000000; // note log2_5/scale is the actual value
result = x * log2_5;
output = (result - (result % scale)) / scale;
By reducing result by result % scale, dividing it by scale will be an integer division, not a float.
for a simple, efficient and mathematically elegant way... floor(x*log2(5))
Since x has integer values 1 to 100, various tests can to made to find the "best" that uses an integer multiply and a divide by power_of_2.
f(x) = x*a integer_divide power_of_2
For
f(x) = floor(x*log2(5)) = floor(x*some_float_c) the value of some_float_c is bounded by 100 minimum and maximums below.
x f(x) mn mx
f(x)/x (f(x) + 1)/x
1 2 2.00000 3.00000
2 4 2.00000 2.50000
3 6 2.00000 2.33333
...
59 136 2.30508 2.32203
...
87 202 2.32184 2.33333
...
98 227 2.31633 2.32653
99 229 2.31313 2.32323
100 232 2.32000 2.33000
The maximum min is 2.32184 and the minimum max is 2.32203, :
2.32184... <= some_float_c < 2.32203...
Since we cannot use float, find some_integer/some_power_of_2
2.32184... <= some_integer/some_power_of_2 < 2.32203...
ceil(some_power_of_2 * 2.32184...) <= some_integer < floor(some_power_of_2 * 2.32203...)
min max
2.32184 2.32203
2 5 4
4 10 9
8 19 18
...
1024 2378 2377
2048 4756 4755
4096 9511 9511 < first one where min <= max
8192 19021 19022
So 9511/4096 is the "simplest" and is a "best" candidate.
f(x) = (x*9511) integer_divide_by_power_of_2 4096
// In C
unsigned y = (x*9511u) >> 12;
Here is a very rough approximation, but it can help if you want to obtain it mentally
5^3 = 125
2^7 = 128
So for raising to the power of n:
5^n ~~ 2^(7n/3)
So 5^12 is near 2^28 might require up to 29 bits.
It's a bit overestimated because 2^7 > 5^3, so 28 bits are enough, a good usage is to simply round the fraction upper.
If I evaluate in Smalltalk:
(1 to: 50) reject: [:i | (5 raisedTo: i) highBit = (i*7/3) ceiling].
I get:
#(31 34 37 40 43 46 49)
You see that the very simple formulation works up to 5^30 which is not that bad.

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.

Resources