Decaying value over time expontentially - c#

I want to create a sorting algorithm that takes an items score (based on upvotes/downvotes) and sorts them based on an invisble underlying score that take time decay into account.
Being from the analytic philosophy side, my mathematical algorithms aren't always the best. What is a simple elegant way to solve for InverseTimeRelationship(currentItem.CreationDate) in the following example:
class Item()
{
int upvotes;
int downvotes;
int SortScore;
DateTime CreationDate;
}
var currentItem = GetSomeSpecificItemMethod();
int Score = currentItem.upvotes - currentItem.downvotes;
currentItem.SortScore = Score * InverseTimeRelationship(currentItem.CreationDate);
SortItemsBySortScore(Item[]);
InverseTimeRelationship(DateTime CreationDate)
{
//Code To Write
}
The hope being that after a day, the SortScore would be a little lower, but after say 2-3 days no matter how many votes it has, it will disappear from the top of the list/front page.

You can take a look at the algorithm reddit uses. It seems to be what you want.

Perhaps:
e^-x (= 1/e^x)
See this image (from Wikipedia).
And here's code:
double InverseTimeRelationship(DateTime CreationDate)
{
double HowFast = 0.1;
return Math.Exp(-DateTime.Now.Subtract(CreationDate).Days * HowFast);
}
And you can try it with:
Text = InverseTimeRelationship(DateTime.Today.AddDays(-3)).ToString();

Related

C# , How to output specific array searches?

The program I am creating prompts the user to enter an amount of months, the amount of work absences he/she has had in each month, and the amount of absences allowed per month. It is supposed to calculate the average amount of work absences by an employee as well as the amount of times that he/she went over the max absences allowed.
I was able to calculate the average with an array loop but was having issues with the times he/she has gone over the max absences. I am using the binary search method but have trouble outputting the specific amount of months that the employee has gone over the allowed absence amount.
This is my current code for that section:
for (int i = 0; i < numbOfAbsences.Length; i++)
{
sum += numbOfAbsences[i];
averageAbsences = (sum / numbOfMonths);
Console.WriteLine("Employee was absent " + averageAbsences + " times per month.");
}
a = Array.BinarySearch(numbOfAbsences, maxAbsences);
if (a >= maxAbsences)
{
}
I am unsure of what would go under the last set of brackets, as I am not trying to point out whether the max amount was exceeded but rather the amount of times that it was.
Thank you for the help in advanced.
First off, the question is not clearly stated. It boils down to this:
"What's a good way to take an int array of sums and divide them all by a count to produce a double array of averages? Also, how can I count the values of an int array greater than a threshold? (Here's what I've got so far: )"
Second, the code snippet is very confusing. More precisely... It's not indented correctly. Not all of the variables used are defined, so we have to guess what they are. The variable names aren't very descriptive, so one has to look at how each variable is used to understand it. Most importantly however, this is no encapsulation. No objects, no functions... just raw code that you need to read every line of very carefully to understand.
Contrast the snippet with this:
using System;
using System.Linq;
namespace ArraySearch_StackOverflow
{
class Program
{
static void Main(string[] args)
{
int[] employeeAbsencesEachMonth = new int[] { 1, 2, 3, 4, 5, 6 };
int maxAbsencesAllowedPerMonth = 3;
double averageAbsencesPerMonth = GetAverageAbsencesPerMonth(employeeAbsencesEachMonth);
Console.WriteLine($"Employee's Average Absences Per Month: {averageAbsencesPerMonth}"); /* 3 */
int numTimesMaxAbsencesExceeded = GetNumMaxAbsencesViolations(employeeAbsencesEachMonth, maxAbsencesAllowedPerMonth);
Console.WriteLine($"Number of Times Employee Exceeded Max Absence Limit: {numTimesMaxAbsencesExceeded}"); /* 3 */
Console.WriteLine("\nPress any key to continue...");
Console.ReadKey();
}
private static double GetAverageAbsencesPerMonth(int[] employeeAbsencesEachMonth)
{
// ???
throw new NotImplementedException();
}
private static int GetNumMaxAbsencesViolations(int[] employeeAbsencesEachMonth, int maxAbsencesAllowedPerMonth)
{
// ???
throw new NotImplementedException();
}
}
}
This snippet is extremely clear. Even without a description, it's immediately apparent what's being asked, and how to tell if an answer is correct. Because the questions have been translated into a function signature and the context has been translated into a driver in which the functions are called, complete with setup and an expected result.
Handily, this implies a simple format for the answer, creating a good chance you can copy-paste it directly into your code:
private static double GetAverageAbsencesPerMonth(int[] employeeAbsencesEachMonth)
{
return employeeAbsencesEachMonth.Sum() / employeeAbsencesEachMonth.Length;
}
private static int GetNumMaxAbsencesViolations(int[] employeeAbsencesEachMonth, int maxAbsencesAllowedPerMonth)
{
return employeeAbsencesEachMonth.Count(x => x > maxAbsencesAllowedPerMonth);
}

Working with micro changes in floats/doubles

The last couple of days have been full with making calculations and formulas and I'm beginning to lose my mind (a little bit). So now I'm turning to you guys for some insight/help.
Here's the problem; I'm working with bluetooth beacons whom are placed all over an entire floor in a building to make an indoor GPS showcase. You can use your phone to connect with these beacons, which results in receiving your longitude and latitude location from them. These numbers are large float/double variables, looking like this:
lat: 52.501288451787076
lng: 6.079107635606511
The actual changes happen at the 4th and 5th position after the point. I'm converting these numbers to the Cartesian coordinate system using;
x = R * cos(lat) * cos(lon)
z = R *sin(lat)
Now the coordinates from this conversion are kind of solid. They are numbers with which I can work with. I use them in a 3d engine (Unity3d) to make a real-time map where you can see where someone is walking.
Now for the actual problem! These beacons are not entirely accurate. These numbers 'jump' up and down even when you lay your phone down. Ranging from, let's assume the same latitude as mentioned above, 52.501280 to 52.501296. If we convert this and use it as coordinates in a 3d engine, the 'avatar' for a user jumps from one position to another (more small jumps than large jumps).
What is a good way to cope with these jumping numbers? I've tried to check for big jumps and ignore those, but the jumps are still too big. A broader check will result in almost no movement, even when a phone is moving. Or is there a better way to convert the lat and long variables for use in a 3d engine?
If there is someone who has had the same problem as me, some mathematical wonder who can give a good conversion/formula to start with or someone who knows what I'm possibly doing wrong then please, help a fellow programmer out.
Moving Average
You could use this: (Taken here: https://stackoverflow.com/a/1305/5089204)
Attention: Please read the comments to this class as this implementation has some flaws... It's just for quick test and show...
public class LimitedQueue<T> : Queue<T> {
private int limit = -1;
public int Limit {
get { return limit; }
set { limit = value; }
}
public LimitedQueue(int limit)
: base(limit) {
this.Limit = limit;
}
public new void Enqueue(T item) {
if (this.Count >= this.Limit) {
this.Dequeue();
}
base.Enqueue(item);
}
}
Just test it like this:
var queue = new LimitedQueue<float>(4);
queue.Enqueue(52.501280f);
var avg1 = queue.Average(); //52.50128
queue.Enqueue(52.501350f);
var avg2 = queue.Average(); //52.5013161
queue.Enqueue(52.501140f);
var avg3 = queue.Average(); //52.50126
queue.Enqueue(52.501022f);
var avg4 = queue.Average(); //52.5011978
queue.Enqueue(52.501635f);
var avg5 = queue.Average(); //52.50129
queue.Enqueue(52.501500f);
var avg6 = queue.Average(); //52.5013237
queue.Enqueue(52.501505f);
var avg7 = queue.Average(); //52.5014153
queue.Enqueue(52.501230f);
var avg8 = queue.Average(); //52.50147
The limited queue will not grow... You just define the count of elements you want to use (in this case I specified 4). The 5th element pushes the first out and so on...
The average will always be a smooth sliding :-)

Algorithm to update average transfer rate on-the-go with C#

I have a lengthy method that writes data into a database. It is called repeatedly. I also maintain the counter of records written so far, as well as the total number of records that need to be written as such:
private int currentCount;
private int totalCount;
private double fAverageTransferRate;
bool processingMethod()
{
//Processes one record at a time
DateTime dtNow = DateTime.Now; //Time now
fAverageTransferRate = //?
}
I know that to calculate a transfer rate I need to take the number of records written in one second, right, but here come two questions:
How would I time my calculation exactly at 1 second mark?
And, most of all, how do I calculate an average transfer rate?
PS. I need this done, on the go, so to speak, while this method is running (and not after it is finished.)
You could think about it a different way, since what you're really interested in is the rate of processing records. Therefore, you con't need to make the calculation happen at precisely 1 second intervals. Rather, you need it happen about every second but then know exactly when it happens.
To calculate the average transfer rate, just keep a running count of the number of records you are transferring. If more than 1 second has elapsed since the last time you computed the average, its time to compute the average anew. Zero out the running count when you're done, in preparation for the next round.
Pseudo-code follows:
// somewhere outside:
int lastdonetime = 0;
int numprocessed = 0;
bool processingMethod()
{
DateTime dtNow = DateTime.Now; //Time now
if (lastdonetime == 0) lastdonetime = dtNow;
if (dtNow - lastdonetime > 1) {
fAverageTransferRate = numprocessed / (dtNow - lastdonetime);
// Do what you want with fAverageTransferRate
lastdonetime = dtNow;
numprocessed = 0;
}
}

Can't figure out how to return multiple calculated values (3 values, 2 dependent on first) C#/MVC

Been reading about out/ref and tuple, but for the life of me cannot figure out how to implement a way to return three (3) values (whether within same method that calculates my main value, or with separate methods). I am able to perform a calculation with one value (the main value) which deals with pricing for a service.
Here is a snippet of what I've done to calculate that main value:
public class Calculations
{
public decimal decFinancialAccount(QuoteData quoteData)
{
if (quoteData.StepAssetInformation.FinancialAccountDropDown
== StepAssetInformation.FinancialAccount.None)
return 0;
else if (quoteData.StepAssetInformation.FinancialAccountDropDown
== StepAssetInformation.FinancialAccount.One)
return PriceQuote.priceFinancialAccount;
else if (quoteData.StepAssetInformation.FinancialAccountDropDown
== StepAssetInformation.FinancialAccount.Two)
return (PriceQuote.priceFinancialAccount * 2);
...
else
return 0;
}
public decimal CalculateChapter7(QuoteData quoteData)
{
decimal total = PriceQuote.priceChapter7;
...
total += this.decFinancialAccount(quoteData);
return total;
}
}
The above works out great. It obviously has other decimal's that are added, but you get the idea.
Now, I am wanting to perform additional calculations on the CalculateChapter7 value that is returned.
The first value is a DiscountChapter7 / discount (variable in method?) price: above a certain amount, discounts are applied for every increment of 50. I got no problem listing them all out if I have to (rather than complicating things for myself). There is no set formula for the discounts, I just created an Excel sheet to visualize my discounts (see below).
The second value is a CompareChapter7 / compare (variable in method?) price: for every discounted price I offer, a comparison is made to what other's charge for the same service. Again, there is no formula per se, I just used an Excel sheet to figure those out arbitrarily.
In addition, I'd like to (within the "discount" and "compare") do a simple subtraction to show "savings" (calculated price - discounted price = savings) and "difference" (other attorneys charge - discounted price = difference). I imagine when I get the two values above working that these additional two would be simple.
Here is my Excel sheet (just a small snippet):
A few notes about that:
Between 799 and 999 there are no discounts (the "rounded" column is just to bring those numbers to a 50 increment for my ease of use and are not relevant).
The Excel formulas are pretty straightforward (fee - discounted price = savings; other attorneys charge - discounted price = difference) - which is what I am trying to attain within my code.
Can anyone provide a solid example of how to integrate the "discount" and "comparison" with my calculated price?
Thanks!
I didn't really follow your specific scenario but... if you are trying to return 3 things from a function, you're doing it wrong and your code will be a pain to maintain. Just define a new class that has 3 properties and return an instance of this class.
You need to create a new class that will contain all the return values. If it's not going to be used anywhere else, you could nest the class inside the Calculations class as follows, but that's up to you:
public class Calculations
{
public class Result
{
public decimal Total { get; set; }
public decimal Discount { get; set; }
public decimal Comparison {get; set; }
}
public Result CalculateChapter7(QuoteData quoteData)
{
Result result = new Result();
result.Total = ...;
result.Discount = ...;
result.Comparison = ...;
return result;
}
}
When you do it this way, all three return values are packaged up into a single object which is then returned. Each time you call the method, it creates a new Result object and populates it with all the values for that invocation of the method. So, to read the returned values after calling the method, you would need to read each property out of the returned object. For instance you could do something like this:
Calculations calc = new Calculations();
Calculations.Result result = calc.CalculateChapter7(...);
string output = string.Format("Total = {0}, Discount = {1}, Comparison = {2}", result.Total.ToString(), result.Discount.ToString(), result.Comparison.ToString());

Better algorithm for a date comparison task

I would like some help making this comparison faster (sample below). The sample take each value in an array, attach an hour to a comparison-variable. If no matching value, it's add the value to a second array (which are concatenated later).
if (ticks.TypeOf == Period.Hour)
while (compareAt <= endAt)
{
if (range.Where(d => d.time.AddMinutes(-d.time.Minute) == compareAt).Count() < 1)
gaps.Add(new SomeValue() {
...some dummy values.. });
compareAt = compareAt.AddTicks(ticks.Ticks);
}
This execution is too consuming when came to i.e. hours. There are 365 * 24 = 8760 values at most in this array. In future, there will also be minutes/seconds per month 60*24*31=44640, which means unusable.
If the array most often was complete (which means no gaps/empty slots), it could easily be by-passed with if (range.Count() == (hours/day * days)). Though, that day will not be today.
How would I solve it more effective?
One example: If ther are 7800 values in the array, we miss about 950, right? But can I find just the gaps-endings, and just create the missing values? That would make the o-notation depend on amount of gaps, not the amount of values..
One other welcome answer is just an more effective loop.
[Edit]
Sorry for bad english, I try my best to describe.
Your performance is low because the range lookup is not using any indexing and rechecks the entire range every time.
One way to do this a lot quicker;
if (ticks.TypeOf == Period.Hour)
{
// fill a hashset with the range's unique hourly values
var rangehs = new HashSet<DateTime>();
foreach (var r in range)
{
rangehs.Add(r.time.AddMinutes(-r.time.Minute));
}
// walk all the hours
while (compareAt <= endAt)
{
// quickly check if it's a gap
if (!rangehs.Contains(compareAt))
gaps.Add(new SomeValue() { ...some dummy values..});
compareAt = compareAt.AddTicks(ticks.Ticks);
}
}

Categories