Calculator - Allowing negative numbers in calculation - c#

For a practice assignment I need to create a calculator which can:
Multiply
Divide
Add
Subtract
Handle decimals
Handle negative numbers e.g. (2--3=5)
I have made everything work apart from the handling negative numbers and I dont really know how to do such a thing and thought you may be able to help. Here is my current solving code:
public decimal getResult(string equation)
{
//parse a equation as a string and solve it
List<string> numbers = input.Split(opSplit, StringSplitOptions.RemoveEmptyEntries).ToList<string>();
List<string> operators = input.Split(numSplit, StringSplitOptions.RemoveEmptyEntries).ToList<string>();
//remove any decimals from operators list
for (int i = 0; i < operators.Count; i++)
{
if (operators[i] == ".")
{
operators.RemoveAt(i);
}
}
//set total to first values in numbers then remove in from list
decimal total = decimal.Parse(numbers[0]);
numbers.Remove(total.ToString());
int count = 0;
foreach(string s in numbers) {
decimal val = decimal.Parse(s);
string current_operator = operators[count];
MessageBox.Show(current_operator);
switch (current_operator)
{
case "+":
total += val;
break;
case "-":
total -= val;
break;
case "x":
total *= val;
break;
case "/":
total /= val;
break;
}
if (count != operators.Count-1)
{
count++;
}
}
return total;
}
My equations are inputed in this format.
1+2-3*4/5

First of all: right now you're not taking into account the order of operations, which is a very bad idea.
I assume you want to do something like this: -3 + -5, correct?
Here are a few assumptions that you can make:
Do not set the initial value equal to the first value
Set total = 0 instead. That way, if you start with -5, you have the equation 0 - 5 which is already correct and there's no hassle with the initial value.
Simplify the mathematical operations
-3 + -5 is the same as 0 - 3 - 5. Take advantage of this: parse your operators and check if you have two operators following eachother. If you have this: simplify the operation and you're good to go.
For good measure:
+-------------+
| op | op | = |
+-------------+
| + | + | + |
| + | - | - |
| - | + | - |
| - | - | + |
+-------------+

Related

how is this algorithm counting all the unique integers?

below I have an algorithm that counts all the unique integers in an ordered array, but I am not sure how it is doing it using binary search? is anyone able to explain how? thanks.
int unique(int[] a) {
int i = 0;
int count = 0;
while (i < a.length) {
i = nextIndex(a, i, a[i]);
count++;
}
return count;
}
int nextIndex(int[] a, int l, int target) {
int r = a.length - 1;
while (l <= r) {
int mid = l + (r - l) / 2;
if (a[mid] == target) l = mid + 1;
else r = mid - 1;
}
return r + 1;
}
JonasH has posted the actual answer about how this works.
But I was interested to see how much faster (if at all) a binary search would be compared to using Distinct() or a linear search.
Here's the code I used to benchmark it:
using System;
using System.Linq;
using BenchmarkDotNet.Attributes;
namespace ConsoleApp1;
public class UnderTest
{
public UnderTest()
{
const int NUM_VALUES = 1_000_000;
const double PROBABLILITY_OF_CHANGE = 0.00001;
_data = new int[NUM_VALUES];
var rng = new Random(98891); // Fixed seed.
for (int value = 0, i = 0; i < NUM_VALUES; ++i)
{
_data[i] = value;
if (rng.NextDouble() <= PROBABLILITY_OF_CHANGE)
++value;
}
// Print out to prove they all return the same value.
Console.WriteLine(usingBinarySearch(_data));
Console.WriteLine(usingDistinct (_data));
Console.WriteLine(usingLinearSearch(_data));
}
[Benchmark]
public void UsingBinarySearch()
{
usingBinarySearch(_data);
}
[Benchmark]
public void UsingDistinct()
{
usingDistinct(_data);
}
[Benchmark]
public void UsingLinearSearch()
{
usingLinearSearch(_data);
}
static int usingBinarySearch(int[] a)
{
int i = 0;
int count = 0;
while (i < a.Length)
{
i = nextIndex(a, i, a[i]);
count++;
}
return count;
}
static int nextIndex(int[] a, int l, int target)
{
int r = a.Length - 1;
while (l <= r)
{
int mid = l + (r - l) / 2;
if (a[mid] == target) l = mid + 1;
else r = mid - 1;
}
return r + 1;
}
static int usingDistinct(int[] a)
{
return a.Distinct().Count();
}
static int usingLinearSearch(int[] a)
{
int count = 1;
for (int i = 1; i < a.Length; i++)
{
count += a[i - 1] != a[i] ? 1 : 0;
}
return count;
}
readonly int[] _data;
}
For the first test run, I gave it some data where I'd expect the binary search to be significantly faster: An array of 1M ints where the probability of each element's value being larger than the previous was 0.00001 (PROBABLILITY_OF_CHANGE = 0.00001).
Using a random number generator with a fixed seed of 98891 this resulted in there only being 7 distinct values in the array, yielding the following timing results (using .NET 6.0):
| Method | Mean | Error | StdDev |
|------------------ |---------------:|--------------:|--------------:|
| UsingBinarySearch | 251.0 ns | 4.93 ns | 12.64 ns |
| UsingDistinct | 9,341,067.8 ns | 185,888.76 ns | 294,839.27 ns |
| UsingLinearSearch | 1,607,222.2 ns | 51,565.50 ns | 146,282.75 ns |
As you might expect, the binary search is way faster for this case. Of note is that Distinct() is very slow compared to the linear search.
This isn't really a fair comparison because Distinct() will work with unsorted data while the other two algorithms require sorted data, so bear that in mind. If you have unsorted data then the overhead of sorting it for the other algorithms will make Distinct() a better choice. I leave such comparisons as the proverbial exercise for the reader...
Now let's try with PROBABLILITY_OF_CHANGE = 0.001 (resulting in 919 distinct elements):
| Method | Mean | Error | StdDev |
|------------------ |------------:|-----------:|-----------:|
| UsingBinarySearch | 93.08 us | 1.787 us | 4.831 us |
| UsingDistinct | 9,944.12 us | 197.825 us | 356.718 us |
| UsingLinearSearch | 1,503.85 us | 28.239 us | 63.740 us |
Binary search is still significantly faster.
Now with PROBABLILITY_OF_CHANGE = 0.1 (resulting in 100,058 distinct elements):
| Method | Mean | Error | StdDev |
|------------------ |----------:|----------:|----------:|
| UsingBinarySearch | 5.541 ms | 0.1096 ms | 0.1347 ms |
| UsingDistinct | 14.331 ms | 0.5516 ms | 1.6091 ms |
| UsingLinearSearch | 2.319 ms | 0.0422 ms | 0.0782 ms |
Now linear search is faster than binary search.
This goes to show that Distinct() is not a good way to solve this - a linear search is always better (primarily because the data is already sorted - if it wasn't then we'd have to sort it which would change the timings significantly for the other algorithms).
And using a binary search is only worth it if the number of distinct values is relatively low compared to the size of the container.
(Do note the different units output by Benchmark.Net for these runs - ns, us and ms. I realised afterwards that I forgot to specify the units so they were automatically scaled for the fastest benchmark in the run...)
The nextIndex method is essentially a binary search method that searches for the last occurrence of the target value, and then returns the index one larger than this. So the outer loop will iterate and increase the count the same number of times that there are unique values.
Note that I would only use such a complicated method if profiling showed the need for it. The standard method would be myValues.Distinct().Count(), that should be faster for unordered lists, and work for types other than int arrays.
Successive binary searches should have a complexity of O(m log n) where n is the total amount of items, and m the number of unique values. This suggest a linear search should be faster if you have less then log n duplicated values on average. Such a linear search could look something like :
int count = 1;
for(int i = 1; i < a.Count; i++){
count += a[i-1] != a[i] ? 1 : 0;
}
Also keep in mind that there are constant factors at play that can affect the result. As an example, random memory accesses are more expensive than linear access, since it makes caching more difficult. So in some cases a simpler algorithm that matches the hardware better is preferred over a more complex one, and some implementations switch strategies depending on the data set.

mxparser performance for single expression evaluated multiple times

I have a scenario where I need to evaluate one expression 1 million times, but on each iteration the only things that do change are the argument values:
var x1 = new Argument("X1", double.NaN);
var x2 = new Argument("X2", double.NaN);
var x3 = new Argument("X3", double.NaN);
Expression expression = new Expression(
"coalesce(X1, 0) + coalesce(X2, 0) + coalesce(X3, 0)",
x1, x2, x3);
var calculateElapsed = new List<double>();
var getComputingTime = new List<double>();
var s1 = mXparser.currentTimeMillis();
foreach (var i in Enumerable.Range(1, 1000000))
{
x1.setArgumentValue(i % 5 == 0 ? double.NaN : i % 5);
x2.setArgumentValue(i % 7 == 0 ? double.NaN : i % 7);
x3.setArgumentValue(i % 3 == 0 ? double.NaN : i % 3);
var s2 = mXparser.currentTimeMillis();
expression.calculate();
var e2 = mXparser.currentTimeMillis();
calculateElapsed.Add(e2 - s2);
getComputingTime.Add(expression.getComputingTime());
}
var e1 = mXparser.currentTimeMillis();
Based on the run's benchmark statistics, getComputingTime() is measuring significantly smaller values than getCurrentMillis() indicating some sort of pre-evaluation overheads.
-----------------------------------------------------------------------------------
| | Avg(ms) | Median(ms) | Min(ms) | Max(ms) | Total(ms) |
-----------------------------------------------------------------------------------
| getComputingTime | 0.000004 | 0.000000 | 0.000000 | 0.121000 | 4.206000 |
-----------------------------------------------------------------------------------
| calculate() | 0.004300 | 0.000000 | 0.000000 | 131.000000 | 4,300.000000 |
-----------------------------------------------------------------------------------
I am not sure what overhead this should be, since I would assume the expression does not change so we only need to parse once.
Is there some sort of configuration or pattern that would allow me to reduce this overhead cost of calculate() when the expression is the same and only the arguments values are varying?
Max most likely will be the first call of calculate(), where all pre-compilation is done. You are just changing argument values, so mXparser calculates it really fast after the first call of calculate() method. Remove from the stats first iteration and then rerun your test.

Faster way of truncating 0s from long in lieu of % 10

I'm looking to "truncate" 0's from long values.
For example, for long value "1234560000", I'd like to drop the last four 0's (to 123456) and also need to know how many 0's have been dropped.
I can achieve this with a % 10 operations:
void Main()
{
Console.WriteLine(Truncate(1234560000));
}
public static long Truncate(long mantissa)
{
int droppedZeros = 0;
while (mantissa % 10 == 0)
{
mantissa /= 10;
droppedZeros++;
}
return mantissa;
}
This piece of code getting is getting called millions of times and is performance critical and I'm looking for ways to improve performance to achieve the same without modulo (can this be done with bit shifts?).
Per request, I added some benchmarks numbers including a benchmark that performs division with compile time known constant to showcase the relative overhead of the modulo operation:
Method | Mean | Error | StdDev | Median | Gen 0/1k Op | Gen 1/1k Op | Gen 2/1k Op | Allocated Memory/Op |
---------------- |----------:|----------:|----------:|----------:|------------:|------------:|------------:|--------------------:|
DivideNoModulo | 1.863 ms | 0.0431 ms | 0.1272 ms | 1.855 ms | - | - | - | - |
ModuloBasic | 21.342 ms | 0.8776 ms | 2.5876 ms | 20.813 ms | - | - | - | - |
DivisionBasic | 18.159 ms | 1.7218 ms | 5.0768 ms | 15.937 ms | - | - | - | - |
DivisionSmarter | 7.510 ms | 0.5307 ms | 1.5649 ms | 7.201 ms | - | - | - | - |
ModuloSmarter | 8.517 ms | 0.1673 ms | 0.2886 ms | 8.531 ms | - | - | - | - |
StringTruncate | 42.370 ms | 1.7358 ms | 5.1181 ms | 40.566 ms | 1000.0000 | - | - | 8806456 B |
Benchmark code:
[SimpleJob(RunStrategy.ColdStart, 1)]
[MemoryDiagnoser]
public class EncoderBenchmark
{
private long _mantissa;
[Benchmark]
public void DivideNoModulo()
{
for (var i = 0; i < 100000; i++)
{
_mantissa = 12345600000000;
_mantissa /= 100000000;
}
}
[Benchmark]
public void ModuloBasic()
{
for (var i = 0; i < 100000; i++)
{
_mantissa = 12345600000000;
while (_mantissa % 10 == 0)
{
_mantissa /= 10;
}
}
}
[Benchmark]
public void DivisionBasic()
{
for (var i = 0; i < 100000; i++)
{
_mantissa = 12345600000000;
for (;;)
{
long temp = _mantissa / 10;
if (temp * 10 != _mantissa)
break;
_mantissa = temp;
}
}
}
[Benchmark]
public void DivisionSmarter()
{
for (var i = 0; i < 100000; i++)
{
_mantissa = 12345600000000;
for (; ; )
{
long temp = _mantissa / 1000000;
if (temp * 1000000 != _mantissa)
break;
_mantissa = temp;
}
for (; ; )
{
long temp = _mantissa / 10;
if (temp * 10 != _mantissa)
break;
_mantissa = temp;
}
}
}
[Benchmark]
public void ModuloSmarter()
{
for (var i = 0; i < 100000; i++)
{
_mantissa = 12345600000000;
while (_mantissa % 1000000 == 0)
{
_mantissa /= 1000000;
}
while (_mantissa % 10 == 0)
{
_mantissa /= 10;
}
}
}
[Benchmark]
public void StringTruncate()
{
for (var i = 0; i < 100000; i++)
{
_mantissa = 12345600000000;
_mantissa = long.Parse(_mantissa.ToString().TrimEnd('0'));
}
}
}
You'll be very unlikely to get it working efficiently with bit shifting since that's ideal for dividing by powers of two, of which 10 is not one.
A possibility for improvement, where you may often get numbers with lots of trailing zeros, is to use multiple loops to do the work in bigger chunks, such as:
if (mantissa != 0) {
while (mantissa % 1000000 == 0) {
mantissa /= 1000000;
droppedZeros += 6;
}
while (mantissa % 1000 == 0) {
mantissa /= 1000;
droppedZeros += 3;
}
while (mantissa % 10 == 0) {
mantissa /= 10;
droppedZeros++;
}
}
This will usually result in fewer instructions being performed but, as with all optimisations, measure, don't guess! It may be that the added code complexity is not worth the gains you get (if any).
Note that I've also caught the mantissa == 0 case since that will result in an infinite loop in your original code.
Another possibility you may want to consider is if you're doing this operation to the same item multiple times. For example, let's say you have a collection of integers and, each time you need to process one of them, you have to strip off and count the trailing zeros.
In that case, you could actually store them in a different way. For example, consider the (pseudo-code) structure:
struct item:
int originalItem
int itemWithoutZeroes
int zeroCount
Basically, whenever you first receive an item (such as 1234560000), you immediately convert it to the structure once and once only:
{ 1234560000, 123456, 4 }
This provides a cached version of the zero-stripped item so you never have to calculate it again.
So, if you want the stripped mantissa, you just use item.itemWithoutZeros. If you want to output the number in its original form, you can use item.originalItem. And, if you want the count of zeros, use item.zeroCount.
Obviously, this will take up more storage space but you'll often find that optimisation is a time/space trade-off.
A bit faster replace '%' with '*'
public static long T(long mantissa)
{
if (mantissa == 0)
return 0;
int droppedZeros = 0;
for (; ; )
{
long temp = mantissa / 1000000;
if (temp * 1000000 != mantissa)
break;
mantissa = temp;
droppedZeros += 6;
}
for (; ; )
{
long temp = mantissa / 1000;
if (temp * 1000 != mantissa)
break;
mantissa = temp;
droppedZeros += 3;
}
for (; ; )
{
long temp = mantissa / 10;
if (temp * 10 != mantissa)
break;
mantissa = temp;
droppedZeros++;
}
return mantissa;
}
Update your Truncate logic as below.
public static long Truncate(long mantissa)
{
if (mantissa == 0)
return 0;
var mantissaStr = mantissa.ToString();
var mantissaTruncated = mantissaStr.TrimEnd('0');
int droppedZeros = mantissaStr.Length - mantissaTruncated.Length;
return Convert.ToInt64(mantissaTruncated);
}

Populate array with incremental values topping grand total

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);

Recursive Multiplication Method

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.

Categories