我有一个代码:
public class Point
{
public int x;
public int y;
public Point() { x = 0; y = 0; }
public Point(int a, int b) { x = a; y = b; }
}
public struct Coefficients{
public double a;
public double b;
public double c;
public Coefficients(double a, double b, double c)
{
this.a = a;
this.b = b;
this.c = c;
}
public static Coefficients GetFromPoints(Point point1, Point point2)
{
int x1 = point1.x;
int x2 = point2.x;
int y1 = point1.y;
int y2 = point2.y;
double a = y1- y2;
double b = x2 - x1;
double c = x1 * y2 - y1 * x2 ;
double max = Math.Max(Math.Max(a, b), c);
double min= Math.Min(Math.Min(a, b), c);
double divider = Math.Abs(max)> Math.Abs(min)?max:min;
divider = Math.Abs(divider) > 1? divider : 1;
return new Coefficients(a/divider, b/divider, c/divider);
}
}
public class Solution
{
public int MaxPoints(Point[] points)
{
var coef_list = new List<Coefficients>();
for (var x = 0; x < points.Length - 1; x++)
{
for (var y = x + 1; y < points.Length; y++)
{
var coef = Coefficients.GetFromPoints(points[x], points[y]);
coef_list.Add(coef);
}
}
foreach (var item in coef_list) {
Debug.WriteLine(item.a);
Debug.WriteLine(item.b);
Debug.WriteLine(item.c);
Debug.WriteLine(item.GetHashCode());
Debug.WriteLine("---------------");
}
return 0;
}
}
正如你所看到的,我使用了一个结构,并且我评论了奇怪的行为。 如果我有这样的输入数据:
prg.MaxPoints(new Point[] { new Point(4, -1), new Point(4, 0), new Point(4, 5) });
调试输出是:
-0,25
0
1
-450335288
---------------
-0,25
0
1
-450335288
---------------
-0,25
0
1
-450335288
---------------
但如果我改变args。为了:
prg.MaxPoints(new Point[] { new Point(4, 0),new Point(4, -1) , new Point(4, 5) });
调试是:
-0,25
0
1
1697148360
---------------
-0,25
0
1
-450335288
---------------
-0,25
0
1
-450335288
---------------
有一点可以重要的是,在第一种情况下,我们所有的“分隔符”(GetFromPoints方法)都是正的(4,24,20)在第二种情况下,其中一个是负面和其他两个是正面的( - 4,20,24)。 有人可以解释一下吗?
UPD。 当我改变了
return new Coefficients(a/divider, b/divider, c/divider);
到
return new Coefficients(a/divider, 0, c/divider);//anyway in all of these cases 2-nd argument is 0
这意味着0除以负数不是0?
答案 0 :(得分:2)
基本上你得到负零值双倍。但是,结构的运行时默认的GetHashCode似乎盲目地组合了底层字节而不是调用字段的GetHashCode。以下是您所看到的简化版本:
public struct S
{
public double value;
public S(double d)
{
value = d;
}
}
public static void Main(string[] args)
{
double d1 = 0;
double d2 = d1 / -1;
Console.WriteLine("using double");
Console.WriteLine("{0} {1}", d1, d1.GetHashCode());
Console.WriteLine(GetComponentParts(d1));
Console.WriteLine("{0} {1}", d2, d2.GetHashCode());
Console.WriteLine(GetComponentParts(d2));
Console.WriteLine("Equals: {0}, Hashcode:{1}, {2}", d1.Equals(d2), d1.GetHashCode(), d2.GetHashCode());
Console.WriteLine();
Console.WriteLine("using a custom struct");
var s1 = new S(d1);
var s2 = new S(d2);
Console.WriteLine(s1.Equals(s2));
Console.WriteLine(new S(d1).GetHashCode());
Console.WriteLine(new S(d2).GetHashCode());
}
// from: https://msdn.microsoft.com/en-us/library/system.double.epsilon(v=vs.110).aspx
private static string GetComponentParts(double value)
{
string result = String.Format("{0:R}: ", value);
int indent = result.Length;
// Convert the double to an 8-byte array.
byte[] bytes = BitConverter.GetBytes(value);
// Get the sign bit (byte 7, bit 7).
result += String.Format("Sign: {0}\n",
(bytes[7] & 0x80) == 0x80 ? "1 (-)" : "0 (+)");
// Get the exponent (byte 6 bits 4-7 to byte 7, bits 0-6)
int exponent = (bytes[7] & 0x07F) << 4;
exponent = exponent | ((bytes[6] & 0xF0) >> 4);
int adjustment = exponent != 0 ? 1023 : 1022;
result += String.Format("{0}Exponent: 0x{1:X4} ({1})\n", new String(' ', indent), exponent - adjustment);
// Get the significand (bits 0-51)
long significand = ((bytes[6] & 0x0F) << 48);
significand = significand | ((long) bytes[5] << 40);
significand = significand | ((long) bytes[4] << 32);
significand = significand | ((long) bytes[3] << 24);
significand = significand | ((long) bytes[2] << 16);
significand = significand | ((long) bytes[1] << 8);
significand = significand | bytes[0];
result += String.Format("{0}Mantissa: 0x{1:X13}\n", new String(' ', indent), significand);
return result;
}
输出:
使用双
0 0
0:符号:0(+)
指数:0xFFFFFC02(-1022)
尾数:0x00000000000000 0
0:符号:1( - )
指数:0xFFFFFC02(-1022)
尾数:0x0000000000000Equals:True,Hashcode:0,0
使用自定义结构
假
346948956个
-1800534692
我定义了两个双重的一个是&#34; normal&#34;零和另一个是&#34;否定&#34;零。两者之间的区别在于双符号位。除字节级别外,这两个值在所有明显的方式(Equals比较,GetHashCode,ToString表示)中是相等的。然而,当它们被放入自定义结构时,运行时的GetHashCode方法只是组合原始位,即使它们包含相等的值,也为每个结构提供不同的哈希码。 Equals做同样的事情,得到一个假结果。
我承认这有点大问题。解决方案是确保您重写Equals和GetHashCode以获得所需的正确相等。
实际上已经提到类似的问题before显然运行时只在结构的字段全8字节宽时才这样做。