How to Convert Any Generic Numeric into a Double

Is there a way to convert any generic Numeric into a Double?

Just for purposes of syntactical illustration, here's an example of making this a generic and arriving at a Double for all three types:

func f<T:Numeric>(_ i: T) {
var d = 0.0
switch i {
case let ii as Int:
d = Double(ii)
case let ii as Int32:
d = Double(ii)
case let ii as Double:
d = ii
default:
fatalError("oops")
}
print(d)
}

But whether this is better than overloading is a matter of opinion. In my view, overloading is far better, because with the generic we are letting a bunch of unwanted types in the door. The Numeric contract is a lie. A triple set of overloads for Double, Int, and Int32 would turn the compiler into a source of truth.

How to cast a value of generic type T to double without boxing?

NOTE: There was a bug in my initial code for instance-based code generation. Please re-check the code below. The changed part is the order of loading values onto the stack (ie. the .Emit lines). Both the code in the answer and the repository has been fixed.

If you want to go the route of code generation, as you hint to in your question, here's sample code:

It executes ConsumeValue (which does nothing in my example) 10 million times, on an array of ints and an array of booleans, timing the execution (it runs all the code once, to remove JIT overhead from skewing the timing.)

The output:

F1 ints = 445ms         <-- uses Convert.ToDouble
F1 bools = 351ms
F2 ints = 159ms <-- generates code on each call
F2 bools = 167ms
F3 ints = 158ms <-- caches generated code between calls
F3 bools = 163ms

Roughly 65% less overhead with code generation.

The code:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;

namespace ConsoleApplication15
{
class Program
{
public static void F1<T>(IList<T> values) where T : struct
{
foreach (T value in values)
ConsumeValue(Convert.ToDouble(value));
}

public static Action<T> GenerateAction<T>()
{
DynamicMethod method = new DynamicMethod(
"action", MethodAttributes.Public | MethodAttributes.Static,
CallingConventions.Standard,
typeof(void), new Type[] { typeof(T) }, typeof(Program).Module,
false);
ILGenerator il = method.GetILGenerator();

il.Emit(OpCodes.Ldarg_0); // get value passed to action
il.Emit(OpCodes.Conv_R8);
il.Emit(OpCodes.Call, typeof(Program).GetMethod("ConsumeValue"));
il.Emit(OpCodes.Ret);

return (Action<T>)method.CreateDelegate(typeof(Action<T>));
}

public static void F2<T>(IList<T> values) where T : struct
{
Action<T> action = GenerateAction<T>();
foreach (T value in values)
action(value);
}

private static Dictionary<Type, object> _Actions =
new Dictionary<Type, object>();
public static void F3<T>(IList<T> values) where T : struct
{
Object actionObject;
if (!_Actions.TryGetValue(typeof(T), out actionObject))
{
actionObject = GenerateAction<T>();
_Actions[typeof (T)] = actionObject;
}
Action<T> action = (Action<T>)actionObject;
foreach (T value in values)
action(value);
}

public static void ConsumeValue(double value)
{
}

static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();

int[] ints = Enumerable.Range(1, 10000000).ToArray();
bool[] bools = ints.Select(i => i % 2 == 0).ToArray();

for (int pass = 1; pass <= 2; pass++)
{
sw.Reset();
sw.Start();
F1(ints);
sw.Stop();
if (pass == 2)
Console.Out.WriteLine("F1 ints = "
+ sw.ElapsedMilliseconds + "ms");

sw.Reset();
sw.Start();
F1(bools);
sw.Stop();
if (pass == 2)
Console.Out.WriteLine("F1 bools = "
+ sw.ElapsedMilliseconds + "ms");

sw.Reset();
sw.Start();
F2(ints);
sw.Stop();
if (pass == 2)
Console.Out.WriteLine("F2 ints = "
+ sw.ElapsedMilliseconds + "ms");

sw.Reset();
sw.Start();
F2(bools);
sw.Stop();
if (pass == 2)
Console.Out.WriteLine("F2 bools = "
+ sw.ElapsedMilliseconds + "ms");

sw.Reset();
sw.Start();
F3(ints);
sw.Stop();
if (pass == 2)
Console.Out.WriteLine("F3 ints = "
+ sw.ElapsedMilliseconds + "ms");

sw.Reset();
sw.Start();
F3(bools);
sw.Stop();
if (pass == 2)
Console.Out.WriteLine("F3 bools = "
+ sw.ElapsedMilliseconds + "ms");
}
}
}
}

Note that if you make GenerationAction, F2/3 and ConsumeValue non-static, you have to change the code slightly:

  1. All Action<T> declarations becomes Action<Program, T>

  2. Change the creation of the DynamicMethod to include the "this" parameter:

     DynamicMethod method = new DynamicMethod(
    "action", MethodAttributes.Public | MethodAttributes.Static,
    CallingConventions.Standard,
    typeof(void), new Type[] { typeof(Program), typeof(T) },
    typeof(Program).Module,
    false);
  3. Change the instructions to load the right values at the right times:

     il.Emit(OpCodes.Ldarg_0); // get "this"
    il.Emit(OpCodes.Ldarg_1); // get value passed to action
    il.Emit(OpCodes.Conv_R8);
    il.Emit(OpCodes.Call, typeof(Program).GetMethod("ConsumeValue"));
    il.Emit(OpCodes.Ret);
  4. Pass "this" to the action whenever it is called:

     action(this, value);

Here's the complete changed program for non-static methods:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;

namespace ConsoleApplication15
{
class Program
{
public void F1<T>(IList<T> values) where T : struct
{
foreach (T value in values)
ConsumeValue(Convert.ToDouble(value));
}

public Action<Program, T> GenerateAction<T>()
{
DynamicMethod method = new DynamicMethod(
"action", MethodAttributes.Public | MethodAttributes.Static,
CallingConventions.Standard,
typeof(void), new Type[] { typeof(Program), typeof(T) },
typeof(Program).Module,
false);
ILGenerator il = method.GetILGenerator();

il.Emit(OpCodes.Ldarg_0); // get "this"
il.Emit(OpCodes.Ldarg_1); // get value passed to action
il.Emit(OpCodes.Conv_R8);
il.Emit(OpCodes.Call, typeof(Program).GetMethod("ConsumeValue"));
il.Emit(OpCodes.Ret);

return (Action<Program, T>)method.CreateDelegate(
typeof(Action<Program, T>));
}

public void F2<T>(IList<T> values) where T : struct
{
Action<Program, T> action = GenerateAction<T>();
foreach (T value in values)
action(this, value);
}

private static Dictionary<Type, object> _Actions =
new Dictionary<Type, object>();
public void F3<T>(IList<T> values) where T : struct
{
Object actionObject;
if (!_Actions.TryGetValue(typeof(T), out actionObject))
{
actionObject = GenerateAction<T>();
_Actions[typeof (T)] = actionObject;
}
Action<Program, T> action = (Action<Program, T>)actionObject;
foreach (T value in values)
action(this, value);
}

public void ConsumeValue(double value)
{
}

static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();

Program p = new Program();
int[] ints = Enumerable.Range(1, 10000000).ToArray();
bool[] bools = ints.Select(i => i % 2 == 0).ToArray();

for (int pass = 1; pass <= 2; pass++)
{
sw.Reset();
sw.Start();
p.F1(ints);
sw.Stop();
if (pass == 2)
Console.Out.WriteLine("F1 ints = "
+ sw.ElapsedMilliseconds + "ms");

sw.Reset();
sw.Start();
p.F1(bools);
sw.Stop();
if (pass == 2)
Console.Out.WriteLine("F1 bools = "
+ sw.ElapsedMilliseconds + "ms");

sw.Reset();
sw.Start();
p.F2(ints);
sw.Stop();
if (pass == 2)
Console.Out.WriteLine("F2 ints = "
+ sw.ElapsedMilliseconds + "ms");

sw.Reset();
sw.Start();
p.F2(bools);
sw.Stop();
if (pass == 2)
Console.Out.WriteLine("F2 bools = "
+ sw.ElapsedMilliseconds + "ms");

sw.Reset();
sw.Start();
p.F3(ints);
sw.Stop();
if (pass == 2)
Console.Out.WriteLine("F3 ints = "
+ sw.ElapsedMilliseconds + "ms");

sw.Reset();
sw.Start();
p.F3(bools);
sw.Stop();
if (pass == 2)
Console.Out.WriteLine("F3 bools = "
+ sw.ElapsedMilliseconds + "ms");
}
}
}
}

How to cast generic number type 'T' to CGFloat

As an extension to my answer here, you could achieve this statically through using a 'shadow method' in order to allow Numeric types to coerce themselves to any other Numeric type (given that the initialiser for the destination type is listed as a protocol requirement).

For example, you could define your Numeric protocol like so:

protocol Numeric : Comparable, Equatable {

init(_ v:Float)
init(_ v:Double)
init(_ v:Int)
init(_ v:UInt)
init(_ v:Int8)
init(_ v:UInt8)
init(_ v:Int16)
init(_ v:UInt16)
init(_ v:Int32)
init(_ v:UInt32)
init(_ v:Int64)
init(_ v:UInt64)
init(_ v:CGFloat)

// 'shadow method' that allows instances of Numeric
// to coerce themselves to another Numeric type
func _asOther<T:Numeric>() -> T
}

extension Numeric {

// Default implementation of init(fromNumeric:) simply gets the inputted value
// to coerce itself to the same type as the initialiser is called on
// (the generic parameter T in _asOther() is inferred to be the same type as self)
init<T:Numeric>(fromNumeric numeric: T) { self = numeric._asOther() }
}

And then conform types to Numeric like so:

// Implementations of _asOther() – they simply call the given initialisers listed
// in the protocol requirement (it's required for them to be repeated like this,
// as the compiler won't know which initialiser you're referring to otherwise)
extension Float : Numeric {func _asOther<T:Numeric>() -> T { return T(self) }}
extension Double : Numeric {func _asOther<T:Numeric>() -> T { return T(self) }}
extension CGFloat : Numeric {func _asOther<T:Numeric>() -> T { return T(self) }}
extension Int : Numeric {func _asOther<T:Numeric>() -> T { return T(self) }}
extension Int8 : Numeric {func _asOther<T:Numeric>() -> T { return T(self) }}
extension Int16 : Numeric {func _asOther<T:Numeric>() -> T { return T(self) }}
extension Int32 : Numeric {func _asOther<T:Numeric>() -> T { return T(self) }}
extension Int64 : Numeric {func _asOther<T:Numeric>() -> T { return T(self) }}
extension UInt : Numeric {func _asOther<T:Numeric>() -> T { return T(self) }}
extension UInt8 : Numeric {func _asOther<T:Numeric>() -> T { return T(self) }}
extension UInt16 : Numeric {func _asOther<T:Numeric>() -> T { return T(self) }}
extension UInt32 : Numeric {func _asOther<T:Numeric>() -> T { return T(self) }}
extension UInt64 : Numeric {func _asOther<T:Numeric>() -> T { return T(self) }}

Example usage:

class MyClass<T : Numeric> {

var top : T

init(_ top:T) {
self.top = top
}

func topAsCGFloat() -> CGFloat {
return CGFloat(fromNumeric: top)
}
}

let m = MyClass(Int32(42))
let converted = m.topAsCGFloat()

print(type(of:converted), converted) // prints: CGFloat 42.0

This solution is probably no shorter than implementing a method that switches through every type that conforms to Numeric – however as this solution doesn't rely on runtime type-casting, the compiler will likely have more opportunities for optimisation.

It also benefits from static type-checking, meaning that you cannot conform a new type to Numeric without also implementing the logic to convert that type to another type of Numeric (in your case, you would crash at runtime if the type wasn't handled in the switch).

Furthermore, because of encapsulation, it's more flexible to expand, as the logic to convert types is done in each individual concrete type that conforms to Numeric, rather than a single method that handles the possible cases.

C# Numeric type casting between a generic and Built-in numeric type

If you want to convert an arbitrary value into TYPE you could use

tuple[0] = Convert.ChangeType(value, typeof(TYPE));

ChangeType has already the mappings between all primitive numeric types to convert between each other.

If it's just about assigning the default values (i.e. 0 for numeric types) you can use

tuple[0] = default(TYPE);

Generic that takes only numeric types (int double etc)?

I disagree that this can't be done; it's just that the design I'd propose to do it is a little weird (and involved).

Here's the idea.

The Idea

Define an interface IBytesProvider<T>, with one method:

public interface IBytesProvider<T>
{
byte[] GetBytes(T value);
}

Then implement this in a BytesProvider<T> class with a static Default property.

If this sounds familiar, it's because it's exactly how the EqualityComparer<T> and Comparer<T> classes work (heavily used in plenty of LINQ extension methods).

The Implementation

Here's how I'd propose you set it up.

public class BytesProvider<T> : IBytesProvider<T>
{
public static BytesProvider<T> Default
{
get { return DefaultBytesProviders.GetDefaultProvider<T>(); }
}

Func<T, byte[]> _conversion;

internal BytesProvider(Func<T, byte[]> conversion)
{
_conversion = conversion;
}

public byte[] GetBytes(T value)
{
return _conversion(value);
}
}

static class DefaultBytesProviders
{
static Dictionary<Type, object> _providers;

static DefaultBytesProviders()
{
// Here are a couple for illustration. Yes, I am suggesting that
// in reality you would add a BytesProvider<T> for each T
// supported by the BitConverter class.
_providers = new Dictionary<Type, object>
{
{ typeof(int), new BytesProvider<int>(BitConverter.GetBytes) },
{ typeof(long), new BytesProvider<long>(BitConverter.GetBytes) }
};
}

public static BytesProvider<T> GetDefaultProvider<T>()
{
return (BytesProvider<T>)_providers[typeof(T)];
}
}

The Payoff

Now, finally, once you'd done all this, what you'd do is simply call:

byte[] bytes = BytesProvider<T>.Default.GetBytes(toAdd);

No overloads needed.

Java generics and numeric types

I agree 100% with TofuBeer. But in case you wish to avoid verbosity for time sake, this should also do:

static <T extends Number> T sloppyParseNumber(String str,Class<T> clas) {

if (clas == null) throw new NullPointerException("clas is null");

try {

if(clas.equals(Integer.class)) {
return (T) Integer.valueOf(str);
}
else if(clas.equals(Double.class)) {
return (T) Double.valueOf(str);
}
//so on

catch(NumberFormatException|NullPointerException ex) {
// force call with valid arguments
return sloppyParseNumber("0", clas);
}

throw new IllegalArgumentException("Invalid clas " + clas);

}

But purely from T, you cannot get the type at runtime.



Related Topics



Leave a reply



Submit