views:

54

answers:

4

hello

i have an application project that both managed and unmanaged code runs and i need to use the same algorithm for hashing double values in both systems. so either i will override System.Double.GetHashCode() or use its algorithm in c++ code. i could not find the double.gethashcode algorithm and decided to override the function. but i got a strange error.

Cannot implicitly convert type double to System.Double

here is the code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace System
{
  public struct Double
  {
    unsafe public override int GetHashCode()
    {
      fixed (Double* dd = &this)
      {
        int* xx = (int*)dd;
        return xx[0] ^ xx[1] ;
      }

    }
  }
}

namespace ConsoleApplication1
{
  class Program
  {
    static void Main(string[] args)
    {
      double dd = 123.3444; // line 1
      // Double dd = 123.3444; // line 2
      // Cannot implicitly convert type double to System.Double
      Console.WriteLine(dd.GetHashCode());

      Console.ReadLine();
    }
  }
}

if I uncomment line 2 i get Cannot implicitly convert type double to System.Double error. if i run line 1 then no error occurs but the overriden code never works.

maybe it is very bad thing i am trying. so any one knows about the double.gethashcode algorithm, so i can write equivalent c++ code to get the exact int value?

+3  A: 
public struct Double

That is the first issue. You cannot redefine a predefined type (unless ...).

leppie
i tried with the keyword parial (if you mean that). it did not work either.
bahadir
There is no way to redefine primitive types and still have a running program unless you have provided your own .NET runtime.
leppie
Many hash collections do provide passing a customized hash function into it.
leppie
+4  A: 

This is what I see for Double.GetHashCode():

//The hashcode for a double is the absolute value of the integer representation
//of that double.
// 
[System.Security.SecuritySafeCritical]  // auto-generated
public unsafe override int GetHashCode() { 
    double d = m_value; 
    if (d == 0) {
        // Ensure that 0 and -0 have the same hash code 
        return 0;
    }
    long value = *(long*)(&d);
    return unchecked((int)value) ^ ((int)(value >> 32)); 
}
Kirk Woll
And how exactly do you plan to override it?..... -1 sorry
leppie
@leppie, did you miss the part of the OP's question where he asks, "maybe it is very bad thing i am trying. so any one knows about the double.gethashcode algorithm, so i can write equivalent c++ code to get the exact int value?"
Kirk Woll
@Kirk Woll: point taken +1 :)
leppie
this is the same algorithm i used in the question. haha i had to be patient and try the code in some function and compare results with gethashcode. thank you Kirk :)
bahadir
That works with the current implementation, but you should be cautious about depending on implementation details, as they may change. When sharing a hash code between architectures it would be better to use an algorithm that is independent of either platform. You can of course use the same algorithm as the current implementation, but you should imitate it, not use the built in method.
Guffa
+1  A: 

Use extension methods, Luke.

Lavir the Whiolet
+2  A: 

There is two problems with your custom double type:

  • It contains no data.
  • It doesn't convert to and from double.

The first is solved by simply having a private variable of the type double in the structure.

The second is solved by using implicit converters.

public struct CustomDouble {

  private double _value;

  public override int GetHashCode() {
    byte[] data = BitConverter.GetBytes(_value);
    int x = BitConverter.ToInt32(data, 0);
    int y = BitConverter.ToInt32(data, 4);
    return x ^ y;
  }

  public static implicit operator double(CustomDouble d) {
    return d._value;
  }

  public static implicit operator CustomDouble(double d) {
    return new CustomDouble() { _value = d };
  }

}

Example:

// Use the conversion from double to CustomDouble
CustomDouble d = 3.14;

// Use the CustomDouble.GetHashCode method:
Console.WriteLine(d.GetHashCode()); // 300063655

// Use the conversion from CustomDouble to double:
Console.WriteLine(d); // 3.14
Guffa
a nice advice but your gethashcode seems to be slower compared to the unsafe version. maybe there will be ten thousands of hashing in a second in my app. i need speed. also users will be writing custom c# codes. so they will have to use the name "CustomDouble" instead of "double". but still thanks.
bahadir
@bahadir: If you need speed that badly you can of course use the unsafe version, I just included one to show that it can easily be done without. Similarly I named the class `CustomDouble` to separate it from the built in type, as you should be careful about trying to replacing those. You can replace the `Double` name, but you still can't change the meaning of the `dobule` keyword.
Guffa