Compare variable with hundreds values - c#
I pass a variable with a value of millivolts acquired by a microprocessor connected via serial port, to a class in my app.
The class has to compare the received value "milliV" to many values corresponding to 10 °C increments. I have to do this for accuracy of the output because the output of a thermocouple is not linear. When the value of "milliV is lower than a specific value, then an integration calculation is made between the top and bottom closer values and returns a new value "_tempEx".
This class is working and returns the correct value but I think that beside if/if else and switch, there should be better way to achieve the same result. I have not coded the entire class which should contain approx. 150 comparison values in the range I need to cover.
Moreover, having to do the same for a thermocouple type K, I would end up with hundreds of strings to compare.
Is there a better way to achieve the same result of the method in this class?
public class Termocoppia
{
//milliV#temperature for thermocouple type "J"
double t10=1.019, t20=1.537, t30=2.059, t40=2.585, t50=3.116;
double t60=3.650, t70=4.187, t80=4.726, t90=5.269, t100=5.814;
double t110=6.360, t120=6.909, t130=7.459, t140=8.010, t150=8.562;
double t160=9.115, t170=9.669, t180=10.224, t190=10.779, t200=11.334;
double t210=11.889, t220=12.445, t230=13.000, t240=13.555, t250=14.110;
double t260=14.665, t270=15.219, t280=15.773, t290=16.327, t300=16.881;
//Temperature References
double d10 = 10.00, d20 = 20.00, d30 = 30, d40 = 40, d50 = 50;
double d60 = 60, d70 = 70, d80 = 80, d90 = 90, d100 = 100;
double d110 = 110, d120 = 120, d130 = 130, d140 = 140, d150 = 150;
double d160 = 160, d170 = 170, d180 = 180, d190 = 190, d200 = 200;
double d210=210, d220=220, d230=230, d240=240, d250=250, d260=260;
double d270=270, d280=280, d290=290, d300=300;
// find the highest value and the bottom one to integrate in between withthe received milliV
// returns the value with _tempEx
public double Calcola(double milliV, double _tempEx)
{
if (milliV <= t10)
{
_tempEx = d10;
}
else if (milliV <= t20)
{
_tempEx = d20 - ((t20 - milliV) / ((t20 - t10) / 10));//Questa formula è corretta
}
else if (milliV <= t30)
{
_tempEx = d30 - ((t30 - milliV) / ((t30 - t20) / 10));
}
else if (milliV <= t40)
{
_tempEx = d40 - ((t40 - milliV) / ((t40 - t30) / 10));
}
else if (milliV <= t50)
{
_tempEx = d50 - ((t50 - milliV) / ((t50 - t40) / 10));
}
...........
...........
else if (milliV <= t300)
{
_tempEx = d300 - ((t300 - milliV) / ((t300 - t290) / 10));
}
else
{
}
return _tempEx;
}
I would appreciate answers with sample codes and/or pointing to usable references.
As has been pointed out, you could use arrays:
class Termocoppia
{
// be sure to add all of your values here...
double[] t = { 1.019, 1.537, 2.059, ... };
double[] d = { 10, 20, 30, ... };
public double Calcola(double milliV, double _tempEx)
{
if (milliV <= t[0])
{
// handle first case
_tempEx = d[0];
}
else
{
bool success = false;
int count = t.Length;
// loop through all t values, test, and then calculate
for (int idx = 1; idx < count; idx++)
{
if (milliV <= t[idx])
{
_tempEx = d[idx] -
((t[idx] - milliV) / ((t[idx] - t[idx - 1]) / 10));
success = true;
break;
}
}
if (success == false)
throw new Exception("Unable to calculate _tempEX");
}
return _tempEx;
}
}
The t and d values store the values in an array. The code then just loops through the t array and checks for the condition (milliV <= t[idx]). If this is true, then it uses the corresponding d[idx] and t[idx-1] value to calculate the result.
Related
Linear regression in a list with linq
I have a list of 'steps' that form a ramps series. Eeach step has a start value, an end value and a duration. Here is an example plot: It is guaranteed, that the start value of a subsequent step is equal to the end value. Its a monotonous function. Now I need to get the value at a given time. I have already a working implementation using good old foreach but I wonder if there is some clever way to do it with linq. Perhaps someome has an idea to substitute the GetValueAt function? class Program { class Step { public double From { get; set; } public double To { get; set; } public int Duration { get; set; } } static void Main(string[] args) { var steps = new List<Step> { new Step { From = 0, To = 10, Duration = 20}, new Step { From = 10, To = 12, Duration = 10}, }; const double doubleTolerance = 0.001; // test turning points Debug.Assert(Math.Abs(GetValueAt(steps, 0) - 0) < doubleTolerance); Debug.Assert(Math.Abs(GetValueAt(steps, 20) - 10) < doubleTolerance); Debug.Assert(Math.Abs(GetValueAt(steps, 30) - 12) < doubleTolerance); // test linear interpolation Debug.Assert(Math.Abs(GetValueAt(steps, 10) - 5) < doubleTolerance); Debug.Assert(Math.Abs(GetValueAt(steps, 25) - 11) < doubleTolerance); } static double GetValueAt(IList<Step> steps, int seconds) { // guard statements if seconds is within steps omitted here var runningTime = steps.First().Duration; var runningSeconds = seconds; foreach (var step in steps) { if (seconds <= runningTime) { var x1 = 0; // stepStartTime var x2 = step.Duration; // stepEndTime var y1 = step.From; // stepStartValue var y2 = step.To; // stepEndValue var x = runningSeconds; // linear interpolation return y1 + (y2 - y1) / (x2 - x1) * (x - x1); } runningTime += step.Duration; runningSeconds -= step.Duration; } return double.NaN; } }
You could try Aggregate: static double GetValueAt(IList<Step> steps, int seconds) { var (value, remaining) = steps.Aggregate( (Value: 0d, RemainingSeconds: seconds), (secs, step) => { if (secs.RemainingSeconds > step.Duration) { return (step.To, secs.RemainingSeconds - step.Duration); } else { return (secs.Value + ((step.To - step.From) / step.Duration) * secs.RemainingSeconds, 0); } }); return remaining > 0 ? double.NaN : value; }
let's ignore linq for a moment... for small amounts of steps, your foreach approach is quite effective ... also if you can manage the accessing side to favor ordered sequential access instead of random access, you could optimize the way of accessing the required step to calculate the value... think of an iterator that only goes forward if the requested point is not on the current step if your amount of steps becomes larger and you need to access the values in a random order, you might want to introduce a balanced tree structure for searching the right step element
Need a fix for this implicit cast error in my find median method
Need to find a fix to this implicit cast error to get the code to compile. The code is: // Program calls a method that finds and returns // the median value in an array // The median value is the middle value from largest to smallest // If there are an even number of values, the // median is the mean of the two middle values using System; using static System.Console; class DebugSeven4 { static void Main() { double[] firstArray = { 10, 9, 2, 3, 5, 6 }; double[] secondArray = { 112, 456, 782 }; double[] thirdArray = { 9, 12, 45, 82, 84, 67, 2, 6 }; WriteLine("The median value of the first array is {0}", FindMedian(firstArray)); WriteLine("The median value of the second array is {0}", FindMedian(secondArray)); WriteLine("The median value of the third array is {0}", FindMedian(thirdArray)); } private static double FindMedian(double[] array) { double median; double middle = array.Length / 2; Array.Sort(array); if (array.Length % 2 == 0) median = (double)(array[middle - 1] + array[middle]) / 2; else median = (double) array[middle]; return median; } } The error is "Cannot implicit convert type double to int. Could be missing a cast." but I'm not certain that's the actual problem. It appears to be complaining about the middle variable.
Re: double middle = array.Length / 2; Since array indexes are integers anyway, that should probably just be an integer: int middle = array.Length / 2; Then the casting problem just goes away.
middle variable needs to be an integer since it is actually the index of the middle, and not a value itself. private static double FindMedian(double[] array) { double median; int middleIndex = array.Length / 2; Array.Sort(array); if (array.Length % 2 == 0) median = (array[middleIndex-1] + array[middleIndex]) / 2; else median = array[middleIndex]; return median; } I also removed all necessary castings. Since the results of array[i] is a double there is no need to cast it again as a double after you divide by an integer, like array[i]/2 as the compiler is going to implicitly convert the integer into a double and do the division with also a double as the result. You can further simplify the code with the return keyword private static double FindMedian(double[] array) { int middleIndex = array.Length / 2; Array.Sort(array); if (array.Length % 2 == 0) { return (array[middleIndex - 1] + array[middleIndex]) / 2; } else { return array[middleIndex]; } } or just with the tertiary operator private static double FindMedian(double[] array) { int middleIndex = array.Length / 2; Array.Sort(array); return array.Length % 2 == 0 ? (array[middleIndex - 1] + array[middleIndex]) / 2 : array[middleIndex]; }
Excel RATE function in .NET CORE
I tried to use RATE function in .NET CORE project. There is a Visual Basic library I wanted to use but it does not work with .NET CORE. https://learn.microsoft.com/en-us/dotnet/api/microsoft.visualbasic.financial.rate?view=netframework-4.7.2 Are there any other ways to use it or should I calculate it explicitly? How? I can't find any explanation of this function.
According to #omajid comment I transform official VB code to C#. This is all you need to use Rate method without dependency on Microsoft.VisualBasic.dll which is lacking this method in .NET CORE. private double Rate(double NPer, double Pmt, double PV, double FV = 0, DueDate Due = DueDate.EndOfPeriod, double Guess = 0.1) { double dTemp; double dRate0; double dRate1; double dY0; double dY1; int I; // Check for error condition if (NPer <= 0.0) throw new ArgumentException("NPer must by greater than zero"); dRate0 = Guess; dY0 = LEvalRate(dRate0, NPer, Pmt, PV, FV, Due); if (dY0 > 0) dRate1 = (dRate0 / 2); else dRate1 = (dRate0 * 2); dY1 = LEvalRate(dRate1, NPer, Pmt, PV, FV, Due); for (I = 0; I <= 39; I++) { if (dY1 == dY0) { if (dRate1 > dRate0) dRate0 = dRate0 - cnL_IT_STEP; else dRate0 = dRate0 - cnL_IT_STEP * (-1); dY0 = LEvalRate(dRate0, NPer, Pmt, PV, FV, Due); if (dY1 == dY0) throw new ArgumentException("Divide by zero"); } dRate0 = dRate1 - (dRate1 - dRate0) * dY1 / (dY1 - dY0); // Secant method of generating next approximation dY0 = LEvalRate(dRate0, NPer, Pmt, PV, FV, Due); if (Math.Abs(dY0) < cnL_IT_EPSILON) return dRate0; dTemp = dY0; dY0 = dY1; dY1 = dTemp; dTemp = dRate0; dRate0 = dRate1; dRate1 = dTemp; } throw new ArgumentException("Can not calculate rate"); } private double LEvalRate(double Rate, double NPer, double Pmt, double PV, double dFv, DueDate Due) { double dTemp1; double dTemp2; double dTemp3; if (Rate == 0.0) return (PV + Pmt * NPer + dFv); else { dTemp3 = Rate + 1.0; // WARSI Using the exponent operator for pow(..) in C code of LEvalRate. Still got // to make sure that they (pow and ^) are same for all conditions dTemp1 = Math.Pow(dTemp3, NPer); if (Due != 0) dTemp2 = 1 + Rate; else dTemp2 = 1.0; return (PV * dTemp1 + Pmt * dTemp2 * (dTemp1 - 1) / Rate + dFv); } } private const double cnL_IT_STEP = 0.00001; private const double cnL_IT_EPSILON = 0.0000001; enum DueDate { EndOfPeriod = 0, BegOfPeriod = 1 }
Divide number into defined stacks
So basically I want to split a number, for example: 862 in C# into stacks of 100 (or below with remainder), so it would result in: 100, 100, 100, 100, 100, 100, 100 , 100, 62 I know this is probably easily done, but I've searched and couldn't quite found a solution. I don't quite know what to search as well so that could possibly be the issue. Cheers
This is simple division to get the number of 100 stacks and modulo to get the remainder. int number = 862; int stackSize = 100; var results = Enumerable.Repeat(stackSize, number / stackSize); if (number % stackSize > 0) results = results.Concat(Enumerable.Repeat(number % stackSize, 1)); Console.WriteLine(string.Join(", ", results)); outputs 100, 100, 100, 100, 100, 100, 100, 100, 62 Or as a one liner (credit to spendor) var results = Enumerable.Repeat(stackSize, number / stackSize) .Concat(Enumerable.Repeat(number % stackSize, 1)) .Where(x => x > 0);
This should do the trick: static int[] DivideIntoStacks(int number, int stacksize) { int num = number; List<int> stacks = new List<int>(); while (num > 0) { if (num - stacksize >= 0) { stacks.Add(stacksize); num -= stacksize; } else { stacks.Add(num); break; } } return stacks.ToArray(); } For your example, call the function with: DivideIntoStacks(862, 100) This supplies you with an int[] with the desired values.
while the number is greater than stackSize, add a stackSize to the stack, and subtract that from the number. Once the number is less than stackSize, if there's a remainder, add that to the stack: static void Main(string[] args) { int stackSize = 100; int num = 862; var stacks = new List<int>(); while (num > stackSize) { stacks.Add(stackSize); num -= stackSize; } if (num > 0) { stacks.Add(num); } } I'm sure there's some spiffy LINQ one-liner to do this as well.
int number = 862; int d = number / 100; if(d == 0) { return (d).ToString(); } int r = number % 100; string str = string.Join(",", Enumerable.Repeat("100", d)); if(number % 100 > 0) str = str + ", " + r; return str; Example works for non whole numbers. Just check if value is less then 100 or d == 0(You can check by any of these), so return zero. get the total number of hundreds in number and build a comma separated string. At the end if value has some remainder with 100 append to the string with comma.
construct an array of integers to achieve specific sequence
construct the shortest possible sequence of integers ending with A, using the following rules: the first element of the sequence is 1, each of the successive elements is the sum of any two preceding elements (adding a single element to itself is also permissible), each element is larger than all the preceding elements; that is, the sequence is increasing. For example, for A = 42, a possible solutions is [1, 2, 3, 6, 12, 24, 30, 42]. Another possible solution is [1, 2, 4, 5, 8, 16, 21, 42]. I have written the following but it fails on input of 456, by returning[1,2,4,8,16,32,64,128,200,256,456] , there are no numbers in the sequence that can be added together to get 200. how can I fix the below code? what am I doing wrong? public static int[] hit(int n) { List<int> nums = new List<int>(); int x = 1; while (x < n) { nums.Add(x); x = x * 2; if (x > n) { nums.Add(n - (x / 2)); nums.Add(n); } } nums.Sort(); int[] arr = nums.ToArray(); return arr; }
I know there is gonna be a mathematical proof behind this, but my guess would be along the lines of dividing the number by 2, if it divides equally, repeat the process. If the there is a remainder, it would be 1. So you would have the integer quotient and the quotient plus one. Since one is guaranteed to be in the set, the larger of the 2 numbers is already taken care of. So just repeat the process for the smaller. This problem certainly implies a recursive solution that should be relatively trivial, so I will leave that up to the poster to implement.
I think I got it: public Set<Integer> shortList(int n){ Set<Integer> result = new HashSet<Integer>(); Stack<Integer> stack = new Stack<Integer>(); result.add(n); int num=n, den=0; while(num>1){ while(num > den){ num--; den++; if(num%den==0) stack.push(num); }//num>den if(!stack.isEmpty()){ num = stack.pop(); result.add(num); stack.clear(); }else{ result.add(num); result.add(den); } den=0; } return result; }// Results (unsorted) for 42: [1, 2, 3, 21, 6, 7, 42, 14] for 15: [1, 2, 4, 5, 10, 15] for 310: [1, 2, 155, 4, 5, 310, 10, 124, 62, 31, 15, 30]
Here is my solution in C++ (may be trivially changed to C#): void printSequenceTo(unsigned n) { if (n == 1) { printf("1"); return; } if (n & 1) { int factor = 3; do { if (n % factor == 0) { printSequenceTo(n / factor * (factor-1)); factor = 0; break; } factor += 2; } while (factor * factor <= n); if (factor) printSequenceTo(n-1); } else printSequenceTo(n/2); printf(",%u", n); } Demonstration: http://ideone.com/8lXxc Naturally it could be sped up using a sieve for factorization. Note, this is significant improvement over the accepted answer, but it still is not optimal.
Here is my attempt. It may be optimised, but it shows my idea: private static IEnumerable<int> OptimalSequence(int lastElement) { var result = new List<int>(); int currentElement = 1; do { result.Add(currentElement); currentElement = currentElement * 2; } while (currentElement <= lastElement); var realLastElement = result.Last(); if (lastElement != realLastElement) { result.Add(lastElement); FixCollection(result, lastElement - realLastElement); } return result; } private static void FixCollection(List<int> result, int difference) { for (int i = 0; i < result.Count; i++) { if (result[i] == difference) break; if (result[i] > difference) { result.Insert(i, difference); FixCollection(result, difference - result[i-1]); break; } } } Edit I can't prove it formally but my answer and Chris Gessler's answer give sequences of the same size (at least I checked for numbers between 1 and 10000) because both algorithms compensate odd numbers. Some examples: Number 1535 1,2,3,4,7,8,15,16,31,32,63,64,127,128,255,256,511,512,1024,1535 Number 2047 1,2,3,4,7,8,15,16,31,32,63,64,127,128,255,256,511,512,1023,1024,2047 Number 3071 1,2,3,4,7,8,15,16,31,32,63,64,127,128,255,256,511,512,1023,1024,2048,3071 Number 4095 1,2,3,4,7,8,15,16,31,32,63,64,127,128,255,256,511,512,1023,1024,2047,2048,4095 Number 6143 1,2,3,4,7,8,15,16,31,32,63,64,127,128,255,256,511,512,1023,1024,2047,2048,4096,6143 Number 8191 1,2,3,4,7,8,15,16,31,32,63,64,127,128,255,256,511,512,1023,1024,2047,2048,4095,4096,8191 ============== Number 1535 1,2,4,5,10,11,22,23,46,47,94,95,190,191,382,383,766,767,1534,1535 Number 2047 1,2,3,6,7,14,15,30,31,62,63,126,127,254,255,510,511,1022,1023,2046,2047 Number 3071 1,2,4,5,10,11,22,23,46,47,94,95,190,191,382,383,766,767,1534,1535,3070,3071 Number 4095 1,2,3,6,7,14,15,30,31,62,63,126,127,254,255,510,511,1022,1023,2046,2047,4094,4095 Number 6143 1,2,4,5,10,11,22,23,46,47,94,95,190,191,382,383,766,767,1534,1535,3070,3071,6142,6143 Number 8191 1,2,3,6,7,14,15,30,31,62,63,126,127,254,255,510,511,1022,1023,2046,2047,4094,4095,8190,8191
public static int[] hit(int n) { List<int> nums = new List<int>(); nums.Add(n); int x = 0; int Right = 0; int Left = 0; do { //even num if (n % 2 == 0) { x = n / 2; //result of division is also even 20/2 = 10 if (x % 2 == 0 || n>10 ) { nums.Add(x); n = x; } else { nums.Add(x + 1); nums.Add(x - 1); n = x - 1; } } //numbers that can only be divided by 3 else if (n % 3 == 0) { x = n / 3;//46/3 =155 Right = x * 2;//155*2 = 310 Left = x;//155 nums.Add(Right); nums.Add(Left); n = x; } //numbers that can only be divided by 5 else { x = n / 2; Right = x + 1; Left = x; nums.Add(Right); nums.Add(Left); n = Left; } } while (n > 2); nums.Add(1); nums.Reverse(); int[] arr = nums.ToArray(); return arr; }