创建基于散列的均匀随机数(Create a uniform random number based

2019-07-29 19:42发布

我需要基于由一个字符串和一个长的关键良好的伪随机数。 我应该得到相同的随机数,当我查询使用相同的密钥和也,我如果我查询使用稍微不同的密钥得到一个非常不同的数字,即使说长久的关键是关闭的1我想这个代码和随机号是唯一的,但类似的数字他们似乎相关。

import java.util.Date;
import java.util.Random;
import org.apache.commons.lang3.builder.HashCodeBuilder;

public class HashKeyTest {
    long time;
    String str;
    public HashKeyTest(String str, long time) {
        this.time = time;
        this.str = str;
    }

    @Override
    public int hashCode() {
        return new HashCodeBuilder().append(time).append(str).toHashCode();
    }

    public static void main(String[] args) throws Exception {
        for(int i=0; i<10; i++){
            long time = new Date().getTime();
            HashKeyTest hk = new HashKeyTest("SPY", time);
            long hashCode = (long)hk.hashCode();
            Random rGen = new Random(hashCode);
            System.out.format("%d:%d:%10.12f\n", time, hashCode, rGen.nextDouble());
            Thread.sleep(1);
        }
    }
}

我的解决方案拼凑起来。 这工作得很好,但我不知道它需要这个冗长。

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.nio.ByteBuffer;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;

public class HashKeyTest implements Serializable{

    long time;
    String str;

    public HashKeyTest(String str, long time) {
        this.time = time;
        this.str = str;
    }

    public double random() throws IOException, NoSuchAlgorithmException {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream out = new ObjectOutputStream(bos);
        out.writeObject(this);
        byte[] bytes = bos.toByteArray();
        MessageDigest md5Digest = MessageDigest.getInstance("MD5");
        byte[] hash = md5Digest.digest(bytes);
        ByteBuffer bb = ByteBuffer.wrap(hash);
        long seed = bb.getLong();

        return new Random(seed).nextDouble();
    }

    public static void main(String[] args) throws Exception {
        long time = 0;
        for (int i = 0; i < 10; i++) {
            time += 250L;
            HashKeyTest hk = new HashKeyTest("SPY", time);
            System.out.format("%d:%10.12f\n", time, hk.random());
            Thread.sleep(1);
        }
    }
}

Answer 1:

你说:“我应该得到相同的随机数,当我查询使用相同的密钥和也,我应该得到一个非常不同的号码,如果我查询使用一个稍微不同的关键”。 如果我没有理解你的问题,你不想要一个随机数,而是像一个加密哈希码。

你应该看看路过你有任何的数据通过像SHA或MD5哈希函数。 这会给你的东西是相对于输入看似随意,却总是会给出相同的输入相同的,即使你输入只改变很少会大相径庭。

编辑:为了持续获得双值尝试这样的事情(伪代码):

SHAHashValue v = ComputeSHA( yourObject);
Random r = new Random(v);
the_random_value = r.getNext();

这里的想法是使用SHA哈希值作为种子来初始化随机数发生器。 这是一个很值得你拥有什么,但我不知道你HashBuilder在不同价值观方面产生。 因此,使用SHA哈希,而不是可能改善这种情况。

你也应该考虑,对于0和1之间双打“非常不同”值可能不会立即显现。



Answer 2:

我只想用密钥的本身哈希为“随机”数。 假设一个明智的散列的实现,它有你所提到的所有属性。



Answer 3:

这是一个多少有些令人惊讶的结果。 我本来以为,在种子小的差异应导致随机数的流中的较大差异。 经过思考,我不知道为什么,我以为。

不过,这是很容易固定!

最简单的事情,也许,仅仅是为了让随机数生成器在使用前热身了一下。 你不同的种子产生的比特流开始相似,但很快发散,所以索性扔掉比特流的早期部分应该做的工作。 立即在您创建的行后Random ,补充一点:

rGen.nextLong();

或者,更发散:

for (int j = 0; j < 10; ++j) rGen.nextLong();

简单的测试表明,这得到了更广泛的各种数字。

另一种选择是使用java.security.SecureRandom的随机数发生器。 这确实从类似的输入产生不同的输出的一个更好的工作。 你有一个字节数组种子它; 你可以说像生产一(str + time).getBytes()

另一种办法是把你的种子,然后使用密码散列诸如SHA-256哈希值,然后使用的一些部分作为种子。 散列将采取非常相似的输入和产生非常不同的输出,然后这将使您适当不同的随机比特流。



Answer 4:

我的理解是:

  • 你的对象有两个实例变量-很长time和一个字符串str需要加以考虑来计算随机数
  • 您希望随机数是非常敏感的time的一部分。
  • 同一time + str组合应该产生相同随机数。
  • 这是确定的,如果两个不同的time + str组合产生相同随机数。

从您发布的代码,看来HashCodeBuilder()是不敏感的,你希望它是到time

除了别人的建议,一个想法可以改变time本身以一致的方式。

你可以采取的最后一个数字time (该long键的一部分),并将其移动到某处数量的中间。 例如,你的hashCode()可以是:

@Override
public int hashCode() {
    return (new org.apache.commons.lang.builder.HashCodeBuilder()
            .append(time+((time%10)*100000000)).append(str).toHashCode());
}

(代码是不完全移动的最后一位数字的中间,但在做类似的事情在这个问题的背景下)

但是,这会是一种缓慢。 所以,你可以把它转换为位运营商。

@Override
public int hashCode() {
    return (new org.apache.commons.lang.builder.HashCodeBuilder()
            .append(time+((time & 63l) << 57)).append(str).toHashCode());
}

有点像提取时间的最后6位( time & 63l在前面),并把这些位方式( 57是一种随机的。我只是想转移这些位更显著位置)。 这不符合“移动数字在中间的某个地方”的比喻确切,但类似概念。

如果你只提取最后5位(你会得到更多的变化time & 31l )。 你可以尝试不同的值。 对于张贴在问题的代码,在time & 63l版本返回以下的输出:

1339343005559:-1084202043:0.339762681480
1339343005585:1801482883:0.323979029483
1339343005586:559968862:0.786162684846
1339343005587:-681545159:0.241820545267
1339343005588:-580881900:0.692788956755
1339343005590:1231057354:0.624686671170
1339343005591:-10456667:0.530394885899
1339343005592:1700819920:0.894868466104
1339343005593:459305899:0.149584882259
1339343005595:-2023722143:0.289584988289

其中,符合市场预期,显示在小的变化更方差long键的一部分。



文章来源: Create a uniform random number based on a hash