2

我在我的结构中使用 Random 类CompareTo()以相等的概率选择两个具有相同字段值的结构之一。Random 类使用固定种子进行实例化,以获得可重现的伪随机值序列,以确保无论我使用相同的输入运行多少次,我的程序都会给出相同的精确比较结果。

我正在考虑用内存引用或 GetHashCode() 替换随机数。这样做将保证:

(1) 以相等的概率进行选择,并且

(2) 如果我再次运行该程序,我最终会得到相同的结果吗?

struct MyStruct : IComparable<MyStruct>
{
        private readonly float _param1;
        private readonly float _param2;
        private readonly int _randValue;

        public MyStruct(float param1, float param2)
        {
                _param1 = param1;
                _param2 = param2;
                _randValue = _random.Next();
        }

        public int CompareTo(MyStruct other)
        {
            if (_param1 < other._param1)
            {
                return -1;
            }
            else if (_param1 > other._param1)
            {
                return 1;
            }
            else if (_param2 > other._param2)
            {
                return -1;
            }
            else if (_param2 < other._param2)
            {
                return 1;
            }
            // If both params are equal, then select one of the structs with
            // equal probability
            else if (_randValue < other._randValue)
            {
                return -1;
            }
            else if (_randValue > other._randValue)
            {
                return 1;
            }

            return 0;
        }
}

谢谢 !

4

6 回答 6

16

我在结构的 CompareTo() 中使用 Random 类来以相等的概率选择其中一个结构,当它们具有相同的字段值时。

首先,这是一件非常奇怪的事情。这就像说“当我被要求对一堆数字进行排序时,其中两个都是 12,我随机选择 12 个中的一个来使其更小”。这一点意义都没有。那两个十二是一样的。你没有办法区分一个十二和另一个!

你为什么要做这种奇怪的事情?如果两个值相同,则说它们相同。

在更仔细地阅读您的代码后,我发现您将随机数保留在结构的状态中。如果你想做这件奇怪的事情,那是正确的做法。

我最初认为您正在随机化比较运算符本身那是一件极其危险的事情。允许排序算法对作为全序排序的排序具有很强的依赖性。需要进行比较才能找到自洽的总排序。绝对不能说第一项大于第二项,第二项大于第三项,第三项大于第一项。这违反了比较所需的传递性,并且当给定行为不良的比较操作时,允许排序算法进入无限循环或执行任何其他奇怪的行为。

我正在考虑用内存引用或 GetHashCode() 替换随机数。

这是一个更糟糕的想法。GetHashCode 仅对一件事有用:平衡哈希表。如果您没有平衡哈希表并且您调用 GetHashCode您做错了什么

此外,考虑清楚。您所处的情况是两个结构在其他方面比较相等。合同要求 GetHashCode 为任何两个比较为 equal 的结构返回相同的结果。GetHashCode 明确不是两个相同事物之间歧义的来源!事实上恰恰相反。

这是否能保证以相同的概率进行选择?

没有。GetHashCode 不是随机性来源,也不保证散列码的分布。

如果我再次运行该程序,这是否能保证我最终会得到相同的结果?

绝对不。

于 2011-12-13T23:45:12.847 回答
4

您的代码并不像某些人怀疑的那样危险,因为您在使用数字方面是一致的(它们仅在对象创建时是随机的)。

但我看不到的是,为什么这到底能带来什么好处。

考虑没有_randValue. 假设你有一个结构体(我们称它为2.0 和0.12 x)和另一个结构体(我们称它为2.0 和0.12 ) 。_param1_param2y_param1_param2

好吧,唯一能让和有所不同的方法是你已经向它们添加了 a 。xy_randValue

因为它们是结构,所以它们甚至在赋值和装箱之间没有持久的标识。如果我们这样做,MyStruct z = x我们就没有另一个指针指向x我们有一个全新的MyStruct.

甚至除此之外,它也没有什么区别。

您所做更改的唯一效果是:

  1. 您已经为结构的所有情况添加了额外的内存使用。
  2. 你让排序变得更加昂贵。
  3. 你让建筑变得更加昂贵。
  4. 您使构造成为多线程瓶颈,因为您必须锁定Random.Next().

这些都可能不是特别重要,但过早的悲观情绪是奇怪的根源。

于 2011-12-14T17:14:58.123 回答
2

“内存引用”是指结构的地址吗?如果你想要可预测性,那么你不能使用内存地址。

你打算散列什么?如果您散列结构的属性相等,则散列码也将相等。

我想我很困惑 1)为什么 Random 不适合你和 2)为什么你不只是调用两个具有相等值的结构“相等”?

于 2011-12-13T22:27:56.703 回答
1

我个人更喜欢纯随机数,但要回答您的观点:

  1. 是的,它是一个哈希算法,就像 md5 或 sha 一样(虽然这个算法不是专门为你描述的目的而创建的)
  2. 的,该值将在程序启动之间保持不变(@henk-holterman 是正确的,但不能保证该值仅对字符串保持不变)
  3. GetHashCode 会更快
于 2011-12-13T22:35:59.320 回答
1

既然 Random 类正在做你想做的事,而且你可以播种它以确保你每次都得到相同的值,你为什么要改变它?

我不完全确定您打算使用内存引用做什么,但即使您可以在每次运行代码时指向同一个地址并看到相同的数据,您也不能保证内存中值的公平分布除非你已经用随机函数填充它。

散列函数应该返回一个公平分布的值,但它并不是真正的工作工具——如果你想要一个随机数,请使用一个随机数生成器!

于 2011-12-13T22:25:51.387 回答
0

My reading of your code says that you are using rand has a tie-breaker. I can't see why you would want identical objects differentiated, or even care as to the order of identical objects.

e.g. in this list-

 A
 B
 B
 C

why would you care or want to know which instance of B is first?

I would suggest the better solution would be to add fine grained field that makes sense to the user, say a date created or modified timestamp. You would then have a meaningful tie-breaker, though ties could still occur, I just don't think they would be a problem.

于 2013-02-19T01:43:49.270 回答