Say I have the following functions:
public int Compute(int a, int b, int c)
{
return (a + b +c)/3;
}
public double Compute(double a, double b, double c)
{
return ((a + b + c) / 3.0) / 209;
}
I hope the difference is obvious. A double value needs to be divided by 209 (a constant value) while an integer is not.
What is the best way to combine these two functions in a single one using generics?
I'm not sure it makes sense here.
Generics are the approach to avoid writing the similar code for different object types.
But in your case, I don't see any similar code which could be generalized so keeping the functions different solves the task better.
Short Answer
You cannot turn it into one function.
Long Answer
The only common code you have is this:
return (a + b +c)/
You could use generics and do this at best (not possible with C#):
public static T Compute<T>(T a, T b, T c, T divisorSmall, int divisor)
{
return ((a + b + c) / divisorSmall) / divisor;
// Results in compiler error: Error CS0019 Operator '+' cannot be
// applied to operands of type 'T' and 'T'
}
and use it like this:
Compute(1, 2, 3, 3, 1); // For integers
Compute(1.0, 2.0, 6.0, 3.0, 209); // For doubles
But you cannot do that because you cannot restrict the type T to support arithmetic operation or restrict T to be numeric.
Also, even if it was possible, you do not gain much in this specific case because look how clumsy the usage looks in my hypothetical solution.
You shouldn't do it with generics, but you can test if a, b and c are ints and then select your operation:
private double Compute(double a, double b, double c)
{
/* check if a, b and c are integers int if true double if false */
return (a % 1 == 0 && b % 1 == 0 && c % 1 == 0) ? (a + b + c) / 3 : ((a + b + c) / 3.0) / 209;
}
[TestMethod()]
public void Int()
{
int a = 1;
int b = 2;
int c = 3;
int result = (int)Compute(a, b, c);
int expected = (1 + 2 + 3) / 3;
Assert.AreEqual(expected, result);
}
[TestMethod()]
public void Double()
{
double a = 1.1;
double b = 2.2;
double c = 3.3;
double result = Compute(a, b, c);
double expected = ((1.1 + 2.2 + 3.3) / 3.0) / 209;
Assert.AreEqual(expected, result);
}
Both tests are passing
I have an idea. I can create a method generic which receives an Delegate for each case int and double. This version fiddle works https://dotnetfiddle.net/Q15bYK
public static void Main()
{
Func<double,double,double,double> x = (d1,d2,d3) => {return ((d1 +d2 + d3)/ 3.0) / 209;};
Func<int,int,int,int> y = (i1,i2,i3) => {return (i1 + i2 + i3)/ 3;};
var rsDouble = Compute<double>(1.0,2.0,3.0,x);
Console.WriteLine(rsDouble);
var rsInt = Compute<int>(1,2,3,y);
Console.WriteLine(rsInt);
}
public static T Compute<T>(T a, T b, T c, Func<T,T,T,T> action)
{
return action(a,b,c);
}
But this seems my answer make complicated the situation and I agree with other answers, generics are used to write the similar code for different object types, not to write different code for each parameters.
Related
This is the implementation from Microsoft for Sinh of a Complex
public static Complex Sinh(Complex value) /* Hyperbolic sin */
{
double a = value.m_real;
double b = value.m_imaginary;
return new Complex(Math.Sinh(a) * Math.Cos(b), Math.Cosh(a) * Math.Sin(b));
}
and the implementation for Cosh
public static Complex Cos(Complex value) {
double a = value.m_real;
double b = value.m_imaginary;
return new Complex(Math.Cos(a) * Math.Cosh(b), - (Math.Sin(a) * Math.Sinh(b)));
}
and finally the the implementation for Tanh
public static Complex Tanh(Complex value) /* Hyperbolic tan */
{
return (Sinh(value) / Cosh(value));
}
Source: https://referencesource.microsoft.com/System.Numerics/a.html#e62f37ac1d0c67da
I don't understand why Microsoft implented the Tanh method that way?
It will fail for very large values. E.g.:
tanh(709 + 0i) --> 1, ok
tanh(711 + 0i) --> NaN, failed should be 1
Any ideas how to improve the tanh method that?
For double the Math.Tanh methods works for large values.
The complex tanh method could be implemented like that:
public static Complex Tanh(Complex value)
{
double a = value.Real;
double b = value.Imaginary;
double tanh_a = Math.Tanh(a);
double tan_b = Math.Tan(b);
Complex num = new Complex(tanh_a, tan_b);
Complex den = new Complex(1, tanh_a * tan_b);
return num / den;
}
This will work as well for large values, see https://dotnetfiddle.net/xGWdQt.
Update
As well the complex tan method needs to be re-implemented that it works with larges values (imaginary part):
public static Complex Tan(Complex value)
{
double a = value.Real;
double b = value.Imaginary;
double tan_a = Math.Tan(a);
double tanh_b = Math.Tanh(b);
Complex num = new Complex(tan_a, tanh_b);
Complex den = new Complex(1, -tan_a * tanh_b);
return num / den;
}
See https://dotnetfiddle.net/dh6CSG.
Using the comment from Hans Passant another way to implement the tanh method would be:
public static Complex Tanh(Complex value)
{
if (Math.Abs(value.Real) > 20)
return new Complex(Math.Sign(value.Real), 0);
else
return Complex.Tanh(value);
}
See https://dotnetfiddle.net/QvUECX.
And the tan method:
public static Complex Tan(Complex value)
{
if (Math.Abs(value.Imaginary) > 20)
return new Complex(0, Math.Sign(value.Imaginary));
else
return Complex.Tan(value);
}
See https://dotnetfiddle.net/Xzclcu.
I'm trying to implement Graham algorithm for finding convex hull in C#. It includes the step of sorting points by their angle to the base point. I'm trying to implement it with Array.Sort method using class inherited from Comparer.
Here is the class
class ReversePolarSorter : Comparer<Point>
{
double e = 0.000001;
double m_baseX;
double m_baseY;
public ReversePolarSorter(Point basePoint)
{
m_baseX = basePoint.X;
m_baseY = basePoint.Y;
}
public override int Compare(Point a, Point b)
{
double angleA = Math.Atan2(a.Y - m_baseY, a.X - m_baseX);
double angleB= Math.Atan2(b.Y - m_baseY, b.X - m_baseX);
int result;
if (Math.Abs(angleA - angleB) < e)
result= 0;
else
result= angleA.CompareTo(angleB);
return result;
}
}
And then I'm using it to sort with
Comparer<Point> sorter = new ReversePolarSorter(coords[m_pointsNumber-1]);
Array.Sort<Point>(coords, 0, m_pointsNumber - 2, sorter);
coords is an array of points.
m_pointsNumber is a number of points.
m_pointsNumber-1 is a base point used to compute angles.
It doesn't sort it in a proper order and I can't see the problem. I would appreciate if somebody could to pinpoint it.
I think the compare implementation using epsilon is incorrect.
As we know, if a == b and b == c, then a == c. But this implementation may lead to a == b, b == c, but a < c, which will break the sorting algorithm.
Since you have a base point, you can use rounding rather than epsilon:
class ReversePolarSorter : Comparer<Point>
{
const int precision = 6;
double m_baseX;
double m_baseY;
public ReversePolarSorter(Point basePoint)
{
m_baseX = basePoint.X;
m_baseY = basePoint.Y;
}
double GetAngle(Point p)
{
return Math.Round(Math.Atan2(p.Y - m_baseY, p.X - m_baseX), precision);
}
public override int Compare(Point a, Point b)
{
return GetAngle(a).CompareTo(GetAngle(b));
}
}
Also, note that the third argument of Array.Sort is the length, so if m_pointsNumber is a number of points and point at index m_pointsNumber - 1 is the base point, then you should pass m_pointsNumber - 1 as length:
Array.Sort(coords, 0, m_pointsNumber - 1, sorter);
"The call is ambiguous between the following methods or properties: 'fInt.fInt(int, bool)' and 'fInt.fInt(long, bool)'"
Here are my two constructors:
public fInt(int i, bool scale = true)
{
if (scale) value = i * SCALE;
else value = i;
}
public fInt(long i, bool scale = true)
{
if (scale)
{
if(i > long.MaxValue / SCALE || i < long.MinValue / SCALE)
Debug.LogError("fInt Overflow on creation with scaling");
value = i * SCALE;
}
else value = i;
}
Here's how I'm calling one with int using implicit conversion:
fInt i = 8;
I would like to be able to use both int and long so that I may avoid an extra check if it's not needed. Any thoughts on how to fix this? Would I simply have to do this:
fInt i = (int)8;
fInt i2 = (long)9;
I'd rather not have the extra typing if I can avoid it. Here are my implicit conversions:
//implicit int to fInt
public static implicit operator fInt(int i)
{
return new fInt(i);
}
//implicit long to fInt
public static implicit operator fInt(long i)
{
return new fInt(i);
}
It appears to be a bug in the Unity3D editor...as the code runs fine in Visual Studio. It only mixes up the signatures when the second parameter is optional.
Consider this simple code in C++/CLI
template <typename T>
T sum (T x, T y)
{
return x + y;
}
int main(array<System::String ^> ^args)
{
int a=4, b=6;
double x=2.3, y=5.2;
Console::WriteLine("Sum of two ints = {0}", sum(a, b));
Console::WriteLine("Sum of two doubles = {0}", sum(x, y));
return 0;
}
Output:
Sum of two ints = 10
Sum of two doubles = 7.5
How can I do this in C# using generics?
You can't. There is no way to apply a generic constraint in C# that will ensure that the given generic type will have a suitable overload of the + operator.
You can remove all static type checking and use reflection or similar to attempt to call the + operator of the given generic type at runtime, realizing that it will simply throw a runtime exception if no applicable operator exists, but that is not equivalent to the C++ code you provided.
There's no simple way of doing it with generics, because generics are not templates. You can do it if you supply the operator yourself, like this:
static T binary_apply<T>(T a, T b, Func<T,T,T> add) {
return add(a, b);
}
int a = 4, b = 6;
double x = 2.3, y = 5.2;
Console.WriteLine("Sum of two ints = {0}", binary_apply(a, b, (i,j)=>i+j));
Console.WriteLine("Sum of two doubles = {0}", binary_apply(x, y, (i,j)=>i+j));
Of course this defeats the purpose of having add<T>() in the first place, because you pass an implementation of the addition as a lambda. You can do this dynamically, too, but that is not the same as having the addition resolved by the compiler:
static T add<T>(T a, T b) {
var p0 = Expression.Parameter(typeof(T));
var p1 = Expression.Parameter(typeof(T));
var ae = Expression.Add(p0, p1);
var f = (Func<T,T,T>)Expression.Lambda(ae, p0, p1).Compile();
return f(a, b);
}
int a = 4, b = 6;
double x = 2.3, y = 5.2;
Console.WriteLine("Sum of two ints = {0}", add(a, b));
Console.WriteLine("Sum of two doubles = {0}", add(x, y));
Demo on ideone.
I have a struct called "Complex" in my project (I build it with using C#) and as the name of the struct implies, it's a struct for complex numbers. That struct has a built-in method called "Modulus" so that I can calculate the modulus of a complex number. The things are quite easy up to now.
The thing is, I create an array out of this struct and I want to sort the array according to the modulus of the complex numbers contained.(greater to smaller). Is there a way for that?? (Any algorithm suggestions will be welcomed.)
Thank you!!
Complex[] complexArray = ...
Complex[] sortedArray = complexArray.OrderByDescending(c => c.Modulus()).ToArray();
First of all, you can increase performances comparing squared modulus instead of modulus.
You don't need the squared root: "sqrt( a * a + b * b ) >= sqrt( c * c + d * d )" is equivalent to "a * a + b + b >= c * c + d * d".
Then, you can write a comparer to sort complex numbers.
public class ComplexModulusComparer :
IComparer<Complex>,
IComparer
{
public static readonly ComplexModulusComparer Default = new ComplexModulusComparer();
public int Compare(Complex a, Complex b)
{
return a.ModulusSquared().CompareTo(b.ModulusSquared());
}
int IComparer.Compare(object a, object b)
{
return ((Complex)a).ModulusSquared().CompareTo(((Complex)b).ModulusSquared());
}
}
You can write also the reverse comparer, since you want from greater to smaller.
public class ComplexModulusReverseComparer :
IComparer<Complex>,
IComparer
{
public static readonly ComplexModulusReverseComparer Default = new ComplexModulusReverseComparer();
public int Compare(Complex a, Complex b)
{
return - a.ModulusSquared().CompareTo(b.ModulusSquared());
}
int IComparer.Compare(object a, object b)
{
return - ((Complex)a).ModulusSquared().CompareTo(((Complex)b).ModulusSquared());
}
}
To sort an array you can then write two nice extension method ...
public static void SortByModulus(this Complex[] array)
{
Array.Sort(array, ComplexModulusComparer.Default);
}
public static void SortReverseByModulus(this Complex[] array)
{
Array.Sort(array, ComplexModulusReverseComparer.Default);
}
Then in your code...
Complex[] myArray ...;
myArray.SortReverseByModulus();
You can also implement the IComparable, if you wish, but a more correct and formal approach is to use the IComparer from my point of view.
public struct Complex :
IComparable<Complex>
{
public double R;
public double I;
public double Modulus() { return Math.Sqrt(R * R + I * I); }
public double ModulusSquared() { return R * R + I * I; }
public int CompareTo(Complex other)
{
return this.ModulusSquared().CompareTo(other.ModulusSquared());
}
}
And then you can write the ReverseComparer that can apply to every kind of comparer
public class ReverseComparer<T> :
IComparer<T>
{
private IComparer<T> comparer;
public static readonly ReverseComparer<T> Default = new ReverseComparer<T>();
public ReverseComparer<T>() :
this(Comparer<T>.Default)
{
}
public ReverseComparer<T>(IComparer<T> comparer)
{
this.comparer = comparer;
}
public int Compare(T a, T b)
{
return - this.comparer.Compare(a, b);
}
}
Then when you need to sort....
Complex[] array ...;
Array.Sort(array, ReverseComparer<Complex>.Default);
or in case you have another IComparer...
Complex[] array ...;
Array.Sort(array, new ReverseComparer<Complex>(myothercomparer));
RE-EDIT-
Ok i performed some speed test calculation.
Compiled with C# 4.0, in release mode, launched with all instances of visual studio closed.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
namespace TestComplex
{
class Program
{
public struct Complex
{
public double R;
public double I;
public double ModulusSquared()
{
return this.R * this.R + this.I * this.I;
}
}
public class ComplexComparer :
IComparer<Complex>
{
public static readonly ComplexComparer Default = new ComplexComparer();
public int Compare(Complex x, Complex y)
{
return x.ModulusSquared().CompareTo(y.ModulusSquared());
}
}
private static void RandomComplexArray(Complex[] myArray)
{
// We use always the same seed to avoid differences in quicksort.
Random r = new Random(2323);
for (int i = 0; i < myArray.Length; ++i)
{
myArray[i].R = r.NextDouble() * 10;
myArray[i].I = r.NextDouble() * 10;
}
}
static void Main(string[] args)
{
// We perform some first operation to ensure JIT compiled and optimized everything before running the real test.
Stopwatch sw = new Stopwatch();
Complex[] tmp = new Complex[2];
for (int repeat = 0; repeat < 10; ++repeat)
{
sw.Start();
tmp[0] = new Complex() { R = 10, I = 20 };
tmp[1] = new Complex() { R = 30, I = 50 };
ComplexComparer.Default.Compare(tmp[0], tmp[1]);
tmp.OrderByDescending(c => c.ModulusSquared()).ToArray();
sw.Stop();
}
int[] testSizes = new int[] { 5, 100, 1000, 100000, 250000, 1000000 };
for (int testSizeIdx = 0; testSizeIdx < testSizes.Length; ++testSizeIdx)
{
Console.WriteLine("For " + testSizes[testSizeIdx].ToString() + " input ...");
// We create our big array
Complex[] myArray = new Complex[testSizes[testSizeIdx]];
double bestTime = double.MaxValue;
// Now we execute repeatCount times our test.
const int repeatCount = 15;
for (int repeat = 0; repeat < repeatCount; ++repeat)
{
// We fill our array with random data
RandomComplexArray(myArray);
// Now we perform our sorting.
sw.Reset();
sw.Start();
Array.Sort(myArray, ComplexComparer.Default);
sw.Stop();
double elapsed = sw.Elapsed.TotalMilliseconds;
if (elapsed < bestTime)
bestTime = elapsed;
}
Console.WriteLine("Array.Sort best time is " + bestTime.ToString());
// Now we perform our test using linq
bestTime = double.MaxValue; // i forgot this before
for (int repeat = 0; repeat < repeatCount; ++repeat)
{
// We fill our array with random data
RandomComplexArray(myArray);
// Now we perform our sorting.
sw.Reset();
sw.Start();
myArray = myArray.OrderByDescending(c => c.ModulusSquared()).ToArray();
sw.Stop();
double elapsed = sw.Elapsed.TotalMilliseconds;
if (elapsed < bestTime)
bestTime = elapsed;
}
Console.WriteLine("linq best time is " + bestTime.ToString());
Console.WriteLine();
}
Console.WriteLine("Press enter to quit.");
Console.ReadLine();
}
}
}
And here the results:
For 5 input ...
Array.Sort best time is 0,0004
linq best time is 0,0018
For 100 input ...
Array.Sort best time is 0,0267
linq best time is 0,0298
For 1000 input ...
Array.Sort best time is 0,3568
linq best time is 0,4107
For 100000 input ...
Array.Sort best time is 57,3536
linq best time is 64,0196
For 250000 input ...
Array.Sort best time is 157,8832
linq best time is 194,3723
For 1000000 input ...
Array.Sort best time is 692,8211
linq best time is 1058,3259
Press enter to quit.
My machine is an Intel I5, 64 bit windows seven.
Sorry! I did a small stupid bug in the previous edit!
ARRAY.SORT OUTPEFORMS LINQ, yes by a very small amount, but as suspected, this amount grows with n, seems in a not-so-linear way. It seems to me both code overhead and a memory problem (cache miss, object allocation, GC ... don't know).
You can always use SortedList :) Assuming modulus is int:
var complexNumbers = new SortedList<int, Complex>();
complexNumbers.Add(number.Modulus(), number);
public struct Complex: IComparable<Complex>
{
//complex rectangular number: a + bi
public decimal A
public decimal B
//synonymous with absolute value, or in geometric terms, distance
public decimal Modulus() { ... }
//CompareTo() is the default comparison used by most built-in sorts;
//all we have to do here is pass through to Decimal's IComparable implementation
//via the results of the Modulus() methods
public int CompareTo(Complex other){ return this.Modulus().CompareTo(other.Modulus()); }
}
You can now use any sorting method you choose on any collection of Complex instances; Array.Sort(), List.Sort(), Enumerable.OrderBy() (it doesn't use your IComparable, but if Complex were a member of a containing class you could sort the containing class by the Complex members without having to go the extra level down to comparing moduli), etc etc.
You stated you wanted to sort in descending order; you may consider multiplying the results of the Modulus() comparison by -1 before returning it. However, I would caution against this as it may be confusing; you would have to use a method that normally gives you descending order to get the list in ascending order. Instead, most sorting methods allow you to specify either a sorting direction, or a custom comparison which can still make use of the IComparable implementation:
//This will use your Comparison, but reverse the sort order based on its result
myEnumerableOfComplex.OrderByDescending(c=>c);
//This explicitly negates your comparison; you can also use b.CompareTo(a)
//which is equivalent
myListOfComplex.Sort((a,b) => return a.CompareTo(b) * -1);
//DataGridView objects use a SortDirection enumeration to control and report
//sort order
myGridViewOfComplex.Sort(myGridViewOfComplex.Columns["ComplexColumn"], ListSortDirection.Descending);