本文介绍了如何在带有自定义比较器的c#词典中将浮点数用作键,并四舍五入至最接近的.01?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻求实现IEqualityComparer类,该类存储和比较舍入到最接近0.01的浮点键.特别是,我想确保正确实现GetHashCode方法.我想使它尽可能有效.我可以只使用float值本身作为哈希值吗?

I'm looking to implement an IEqualityComparer class that stores and compares floating point keys that are rounded to the nearest 0.01. In particular, I want to make sure I implement the GetHashCode method correctly. I would like to make this as efficient as possible. Can I use just use the float value itself as it's own hash?

我可以乘以100,转换为int并将int用作键,但是我很好奇这是否可以使用浮点键完成.

I could multiply by 100, cast to int and use an int as a key, but I'm curious if this can be done with float keys.

注意:我会将字典包装在一个类中,以确保只添加或比较四舍五入为.01的值.

Note: I would wrap the dictionary in a class to ensure that only values rounded to .01 are ever added or compared.

跟进问题:如果我使用Decimal(保证总是四舍五入为.01),是否可以在Dictionary中使用带有Decimal键的Decimal的默认比较器?

Follow up question: If I used Decimal (guaranteed to always be rounded to .01) could I just use the default comparer for Decimal with Decimal keys in a Dictionary?

我的第一个想法是尝试这种实现.有什么陷阱吗?

My first thought is to try this implementation. Any pitfalls?

class FloatEqualityComparer : IEqualityComparer<float>
{
    public bool Equals(float b1, float b2)
    {
        int i1 = (int)(b1 * 100);
        int i2 = (int)(b2 * 100);
        if(i1 == i2)
            return true;
        else
            return false;
    }

    public float GetHashCode(float x)
    {
        return x;
    }
}

推荐答案

问题是 GetHashCode 实现.如果两个浮点数可能被视为相等,则它们必须产生相同的哈希码.

The problem is the GetHashCode implementation. If two floats might be considered equal, they must yield the same hash code.

为什么不

sealed class FloatEqualityComparer : IEqualityComparer<float>
{
    public bool Equals(float x, float y) => Math.Round(x, 3) == Math.Round(y, 3);

    public int GetHashCode(float f) => Math.Round(f, 3).GetHashCode();
}

这样做的原因是,如果两个哈希码不同,则不执行相等性测试.这是高效的,可显着提高性能,因为只需对具有相同哈希码的元素对调用 Equals 方法,否则,需要将每个值相互比较,从而得出O(N )的计算复杂度.

The reason for this is that the equality test is not performed if two hash codes are different. This is highly efficient, dramatically improving performance, as the Equals method only has to be called for pairs of elements with identical hash codes as, otherwise, each value would need to be compared to every other resulting in a computational complexity of O(N).

另一种放置方式是,如果两个元素为了相等而相互比较,则它们的哈希码必须冲突.

Another way of putting is that, if two elements should be compared to one another for equality, their hash codes must collide.

最后,我们将清理实现以删除重复的代码,并遵循Microsoft建议的做法来提供自定义相等比较器.

Finally, we'll clean up our implementation to remove duplicate code and follow Microsoft's recommended practices for providing custom equality comparers.

sealed class FloatEqualityComparer : EqualityComparer<float>
{
    public override bool Equals(float x, float y) => GetEquatable(x) == GetEquatable(y);

    public override int GetHashCode(float f) => GetEquatable(f).GetHashCode();

    private static float GetEquatable(float f) => Math.Round(f, 3);
}

这将删除重复的代码,从而防止相等性和哈希逻辑在修改后偏离.它也遵循Microsoft的建议,而不是扩展 EqualityComparer< T> ,而不是实现 IEqualityComparer< T> .后面的更改是BCL公开的平等比较API特有的,绝不是一般准则,它是在此处记录.

This removes duplicate code, preventing equality and hashing logic from drifting apart if revised. It also follows Microsoft's recommendation to prefer extending EqualityComparer<T> over implementing IEqualityComparer<T>. This latter change is peculiar to the equality comparison API exposed by the BCL and by no means a general guideline and is documented here.

这篇关于如何在带有自定义比较器的c#词典中将浮点数用作键,并四舍五入至最接近的.01?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-03 10:46