I have a function that Normalizes any number range to a new range.
Such as
[123,456] to [0,10]
or
[-50,50] to [-1,1]
I need help shifting the middle point of the new range.
I'm using this for a GUI Slider that has a range of [-100,100] but controls a value of [-2,2].
The GUI Slider default is 0 but the value default is 1 (none).
My program is a GUI for a CLI and I'm not able to change that program's value default to 0.
Slider
-100 --------------||-------------- 100
0
Value
-2 | | | -1 | | 0| | | 1 | | 2
Shifted Value
-2 | | -1 | | 0 | 1| | | | | | 2
Normalize
https://dotnetfiddle.net/42jHvM
// Normalize Function
public static double Normalize(double val, double valmin, double valmax, double min, double max, double midpoint)
{
return (((val - valmin) / (valmax - valmin)) * (max - min)) + min;
}
double output = Normalize( 0, // slider input
-100, // input min
100, // input max
-2, // normalize min
2, // normalize max
1 // middle point
);
Shift Middle Point
In my example I use [-100,100] converted to [-2,2].
The middle point of the input [-100,100] is 0.
But I need the output [-2,2] to have a middle point of 1 instead of 0.
So it will be skewed, slower towards -2, faster towards 2.
Example I made in photoshop to visualize the middle point shift using a gradient.
Easing
I tried using an Ease Out Tween to shift the middle point, but I don't know what values to use.
The example output needs to be Min: -2, Mid: 1, Max: 2.
https://dotnetfiddle.net/nfNlBC
It uses:
//t: current time
//b: start value
//c: change in value
//d: duration
After the middle point has been shifted:
Input of -100 should output -2.
Input of -50 should output -0.50?
Input of 0 should output 1.
Input of 50 should output 1.75?
Input of 100 should output 2.
Before
-100 | -50 | -25 | 0 | 25 | 50 | 100
-2 | -1 | -0.5 | 0 | 0.5 | 1 | 2
After approximated
-100 | -50 | -25 | 0 | 25 | 50 | 100
-2 |-0.50 | 0.25 | 1 | 1.25 | 1.75 | 2
Question
How can I modify the Normalize function, or run it's output through a new Shift/Easing function to set the new middle point of the range and readjust the numbers?
I don't understand why do you need such a mapping but the way to do it is:
public static double Normalize( double val, double valmin, double valmax, double min, double max, double midpoint )
{
double mid = ( valmin + valmax ) / 2.0;
if ( val < mid )
{
return ( val - valmin ) / ( mid - valmin ) * ( midpoint - min ) + min;
}
else
{
return ( val - mid ) / ( valmax - mid ) * ( max - midpoint ) + midpoint;
}
}
There's multiple ways this can be done, but if linear interpolation is sufficient, then you can just use some simple stretching and compression of the input parameter with a piecewise function.
public static double Interpolate(double val, double valmin, double valmax, double min, double max)
{
return (max - min) * (val - 0.5 * (valmax + valmin)) / (valmax - valmin) + 0.5 * (max + min);
}
public static double Normalize(double val, double valmin, double valmax, double min, double max, double midpoint)
{
double m = Interpolate(midpoint, valmin, valmax, min, max);
if (val < m) {
return Interpolate(val, valmin, m, min, midpoint);
} else if (val > m) {
return Interpolate(val, m, valmax, midpoint, max);
} else {
return m;
}
}
You should be able to replace Interpolate with something fancier, like one of the easing forms you linked, with the following mappings from your parameter names to theirs:
t = val - 0.5 * (valmax + valmin)
b = 0.5 * (max + min)
c = max - min
d = valmax - valmin
Related
I have an array of floats that would be declared with a variable length. I would like to have a loop that would assign to each element a value proportioned to its position in the array, and the grand total of all the elements should be fixed (to 100).
int arrLength = 5; //this would variate
float grandTotal = 100; //the sum of all the elements should be equal to this
float[] arr = new float[arrLength]();
for(int i=1; i < arr.Length - 1; i++)
{
//logic to attribute values to the elements
}
What I want to achieve is for the elements to represent probabilistic values (in %). The idea is that the lower the index the higher the value they have. So for instance if the length would be equal to 5 the output array should have values like:
arr={30, 25, 20, 15, 10};
As you can see the values are decreasing and total of them is 100. I could I get this type of result regardless of the length of the array?
Thanks.
It seems you need to implement Arithmetic progression (https://en.wikipedia.org/wiki/Arithmetic_progression).
Arithmetic progression has to parameters, start element a0 and difference d.
In your case, the sum of arithmetic progression is grandTotal.
Here we have two unknown variables: a0 and d.
To handle this, we should play with different assumptions.
We could suppose that a0 = d.
In this case
d = 2*grandTotal/(n*(2+n-1))
(n is arrLength).
In your example it will be 2*200/(5*(5+1)) = 6.666666666..., and elements will be 6.66666666, 13.33333333333, 20, 26.666666666, 33.3333333333.
Looks not very pretty.
We could suppose that a0 = 2*d. In this case d = 5 (formula will be d = 2*grandTotal/(n*(2*2+n-1))), and progression is 10, 15, 20, 25, 30.
So, you should implement two loops. First should try different assumptions, e.g. a0 = d, a0 = 2*d, a0 = 3*d, to find "pretty" difference. And then, iterate to fill and array.
We could suppose that a0 = sqrt(grandTotal). In this case d = (2*grandTotal/n-2*a[0])/(n-1) (in your example, it will produce 10, 15, 20, 25, 30).
You may start with second way.
When you get a0 and n, the loop looks like:
for (int i = 0; i < n; ++i)
arr[i] = a0 + d*(n-i-1);
int arrLength = 5;
float grandTotal = 100;
float[] arr = new float[arrLength];
int arrLengthInc = arrLength + 1;
int sum = (arrLengthInc * arrLengthInc / 2) + (arrLengthInc / 2) - 1;
for (int i = 0; i < arr.Length; i++)
{
arr[i] = (i + 2) * grandTotal / sum;
}
// output: // [10, 15, 20, 25, 30]
Console.WriteLine("[{0}]", string.Join(", ", arr));
You need to determine the sum of the whole array, for normalize them.
for example:
2 + 3 + 4 = 9
+-+-+-+-+
| | | |/|
+-+-+-+-+
| | |/|#|
+-+-+-+-+
| |/|#|#|
+-+-+-+-+
|/|#|#|#|
+-+-+-+-+ 4*4 / 2 = 0.5 + 1.5 + 2.5 + 3.5 = 8
The items on the diagonal consume half space.
+-+-+-+-+
| | | |#|
+-+-+-+-+
| | |#|#|
+-+-+-+-+
| |#|#|#|
+-+-+-+-+
|#|#|#|#|
+-+-+-+-+ (4*4 / 2) + (4 / 2) = 0.5 + 1.5 + 2.5 + 3.5 = 10
Index one is missing.
+-+-+-+-+
| | | |#|
+-+-+-+-+
| | |#|#|
+-+-+-+-+
| |#|#|#|
+-+-+-+-+
| |#|#|#|
+-+-+-+-+ (4*4 / 2) + (4 / 2) - 1 = 0.5 + 1.5 + 2.5 + 3.5 = 9
for (int i = 0; i < arr.Length; i++)
{
arr[arr.Length -1 - i] = ((i+2) * arrLength)%grandTotal;
}
//sum of array length elements
int factor=((arrLength*arrlength)+arrLength)/2;
.......
ar[i]=grandTotal/factor*(arrLength-i+1);
I'm following along with this http://www.cs.berkeley.edu/~vazirani/algorithms/chap1.pdf (bottom of page 24). In the book the author describes Al Khwarizmi multiplication algorithm. Here is my implementation
static int RecMultiply(int x, int y)
{
if (y == 0)
return 0;
int z = RecMultiply(x, y / 2);
if (y % 2 == 0)
return 2 * z;
else
return x + 2 * z;
}
I've stepped through the code a couple times and I'm just not grokking it. Why does the bottom else add x to 2 * z? It seems to me that z is used both as a running total and as the "right column" number in the algorithm in the book. Can someone break this code down and explain it please?
Since Multiplication is simple repetitive addition, if y is pair, you can divide it by two, and multiply x by two. (so, 2*2 = 2+2. 2*3 = 2+2+2, 2*4 = 2+2+2+2 ....)
If y is odd, you can subtract 1, to get a y that is pair, and you need to add an x, (basically, 1*y).
Here's a breakdown:
RecMultiply(5,5) :
+- z = RecMultiply(5,2)
| return 5 + 2 * z (=20 +5 =25)
|
|
+-- RecMultiply(5,2) :
+- z = RecMultiply(5,1)
| return 2 * z (=10)
|
+-- RecMultiply(5,1) :
+- z = RecMultiply(5,0)
| return 5 + 0
|
+---RecMultiply(5,0) :
return 0
RecMultiply(5,4) :
+- z = RecMultiply(5,2)
| return 2 * z (=)
|
+-- RecMultiply(5,2) :
+- z = RecMultiply(5,1)
| return 2 * z (=10)
|
+-- RecMultiply(5,1) :
+- z = RecMultiply(5,0)
| return 5 + 0
|
+---RecMultiply(5,0) :
return 0
So, basically, after the recursive bit (that takes care of all the pair multiplications), you might need to add another y, which in the first case above, is 5 for the first call).
Note the special case of y=1, which means x*1 which obviously is 5 in our case. Same logic applies.
You might want to look at it like this, if it helps:
static int RecMultiply(int x, int y)
{
switch (y)
{
case 0:
return 0;
break;
case 1:
return x;
break;
default:
return (y%2 ==0) ? RecMultiply(x, y/2)
: x + RecMultiply(x, y/2);
break;
}
}
I think it denotes the +1 (or odd cases) in a more understandable manner.
It is quite simple.
Z is calculated by multiplying x and half of y.
If y was of even parity (if section) return 2*z = 2 * x * y/2 = x * y (which is original request)
If y was of odd parity (else section) return 2*z + x. Why do we add x??? That is because y/2 will be the same for even and following odd number. So Z would be the same. But, with this if section we are detecting if it's odd or even and in case of odd we add x once more to the result.
I use 'Stimulsoft Reports.Net' to calculate a total price based on multiple items with different prices, ammount and tax-rates. This is my code:
{
Sum
(
DataBandTax,
(
Positions.UnitPrice *
Positions.Amount *
(
Positions.Article.TaxRate +
100
)
) /
100
)
}
Positions is a Bussines-Object, each object of Positions has exactly one Article.
While Positions.UnitPrice and Positions.Amount are multiplied correctly, Stimulsoft uses for every calculation the same Positions.Article.TaxRate, instead the TaxRate which fits to its Position. For example:
Position | UnitPrice | Amount | TaxRate
1 | 100 | 3 | 5
2 | 50 | 10 | 10
3 | 20 | 5 | 3
So the calculation should be:
((100 * 3 * (5 + 100)) / 100)
+ ((50 * 10 * (10 + 100)) / 100)
+ ((20 * 5 * (3 + 100)) / 100)
= 315 + 550 + 103
= 968
Instead stimulsoft calculates this: (In this example it uses only the TaxRate of Position 1)
((100 * 3) + (50 * 10) + (20 * 5))
* (1+(5/100))
= (300 + 200 + 100) * 1.05
= 600 * 1.05
= 630
How do I stop stimulsoft from doing so?
I was able to solve this issue, by placing the TaxRate inside Positions (instead of Positions.Article). Seems like Stimulsoft has a problem when a sum includes object-values and sub-object-values at the same time.
{
Sum
(
DataBandTax,
(
Positions.UnitPrice *
Positions.Amount *
(
Positions.TaxRate +
100
)
) /
100
)
}
I need to find all points that are on a line. I tried Bresenham's algorithm but it doesn't work on the following case:
(0, 0)
.-----------+-----------+-----------.
|...........| | |
|...........| | |
|.....XXXX..| | |
|........XXXX | |
|...........XXXXX | |
+-----------+---XXXX----+-----------+
| |......XXXXX|...........|
| |..........XXXX.........|
| |...........|.XXXXX.....|
| |...........|...........|
| |...........|...........|
`-----------+-----------+-----------ยด
(2, 1)
X is the actual line, . is what Bresenham's algorithm returns, notice the line crosses (1, 0) but it is not marked.
How can I find all the pixels a line goes through efficiently? I don't need this anti-aliased so I think Wu's algorithm is an overkill. The line endpoints are in middle of the pixels.
To reference the algorithm I have is:
int dx = System.Math.Abs(x0 - x1);
int dy = System.Math.Abs(y0 - y1);
int sx = x0 < x1 ? 1 : -1;
int sy = y0 < y1 ? 1 : -1;
int err = dx - dy;
int lx = x0;
int ly = y0;
for(int i = 0; true; i++)
{
Mark(x0, y0);
if(x0 == x1 && y0 == y1)
break;
int e2 = err * 2;
if(e2 > -dy)
{
err -= dy;
x0 += sx;
}
if(e2 < dx)
{
err += dx;
y0 += sy;
}
}
Well, just implement the obvious straightforward algorithm: start from one end of the line, find which side of the starting square it crosses, jump to the corresponding adjacent square... and so on. Walk until you reach the finish square.
The simplest way to implement it in integers would be to switch to superpixel precision: just multiply everything by a constant factor. The difficult part begins when you discover that you don't have enough integer range to multiply it sufficiently... I don't know whether this is the case in your case.
I'm looking for a formula that can spread out numbers in a linear format based on a minimum number, max number and amount of numbers (or dots) between. The catch is, the closer you get to the max, the more numbers should be there.
An example (number will vary and will be about 100 times larger)
Min = 0
Max = 16
AmountOfNumbersToSpread = 6
0 1 2 3 4 5 6 7 8 9 A B C D E F
1 2 3 4 5 6
Thanks for the help in advance.
Based on the answer of Tal Pressman, you can write a distribution function like this:
IEnumerable<double> Spread(int min, int max, int count, Func<double, double> distribution)
{
double start = min;
double scale = max - min;
foreach (double offset in Redistribute(count, distribution))
yield return start + offset * scale;
}
IEnumerable<double> Redistribute(int count, Func<double, double> distribution)
{
double step = 1.0 / (count - 1);
for (int i = 0; i < count; i++)
yield return distribution(i * step);
}
You can use any kind of distribution function which maps [0;1] to [0;1] this way. Examples:
quadratic
Spread(0, 16, 6, x => 1-(1-x)*(1-x))
Output: 0 5.76 10.24 13.44 15.36 16
sine
Spread(0, 16, 6, x => Math.Sin(x * Math.PI / 2))
Output: 0 4.94427190999916 9.40456403667957 12.9442719099992 15.2169042607225 16
Basically, you should have something that looks like:
Generate a random number between 0 and 1.
Implement your desired distribution function (a 1:1 function from [0,1]->[0,1]).
Scale the result of the distribution function to match your desired range.
The exact function used for the second point is determined according to how exactly you want the numbers to be distributed, but according to your requirement, you'll want a function that has more values close to 1 than 0. For example, a sin or cos function.
Tried this on paper and it worked:
given MIN, MAX, AMOUNT:
Length = MAX - MIN
"mark" MIN and MAX
Length--, AMOUNT--
Current = MIN
While AMOUNT > 1
Space = Ceil(Length * Amount / (MAX - MIN))
Current += Space
"mark" Current
By "mark" I mean select that number, or whatever you need to do with it.
Close answer, not quite though, needs to work for larger numbers.
List<int> lstMin = new List<int>();
int Min = 1;
int Max = 1500;
int Length = Max - Min;
int Current = Min;
int ConnectedClient = 7;
double Space;
while(ConnectedClient > 0)
{
Space = Math.Ceiling((double)(Length * ConnectedClient / (Max - Min)));
Current += (int)Space;
ConnectedClient--;
Length--;
lstMin.Add(Current);
}