Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/320.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 将随机字节转换为.NET十进制0..1小数范围_C#_Random - Fatal编程技术网

C# 将随机字节转换为.NET十进制0..1小数范围

C# 将随机字节转换为.NET十进制0..1小数范围,c#,random,C#,Random,我正在玩一个TRNG usb设备,并成功地将随机字节转换为C#中的各种可用数据 我想使用二进制读取器(或其他直接字节->十进制)方法直接从字节创建0..1(例如:0.37327)之间的.NET十进制值 //假设:byte[]具有适当长度的随机\u数据,模式化范围为0..1 十进制值=新的二进制读取器(新的MemoryStream(random_data)).ReadDecimal(); 我在寻找十进制的字节格式,但看起来它可能不是标准格式 这是业余工作,所以我可以接受使用将来可能会改变的东

我正在玩一个TRNG usb设备,并成功地将随机字节转换为C#中的各种可用数据

我想使用二进制读取器(或其他直接字节->十进制)方法直接从字节创建0..1(例如:0.37327)之间的.NET十进制值

//假设:byte[]具有适当长度的随机\u数据,模式化范围为0..1
十进制值=新的二进制读取器(新的MemoryStream(random_data)).ReadDecimal();

我在寻找十进制的字节格式,但看起来它可能不是标准格式
  • 这是业余工作,所以我可以接受使用将来可能会改变的东西。 我已经查看了为示例输入十进制值生成的字节-我看到了负数和精度标志(在last int32中为1Ch max?),但转储编译器常量的最小/最大数据值让我有点困惑,我正在生成高于零值或无效值:

    • 最接近1(.99…9)的分数值:FFFFFF 0F 6102253E 5ECE4F20 00001C000 最接近0(.00…1)的分数值:0100000000000000 00000000 00001C00
    你能帮我找到生成完整分数0..1范围的正确路径吗

    使用“最终”代码编辑,谢谢大家

    下面是我最后使用的C代码,它从一个合适的随机字节流(如TRNG设备、www.random.org或CSPRNG算法)创建一个范围为[0..1]的无偏随机十进制。生成的值看起来很好,边界测试通过,只要我避免了排版和复制/粘贴错误,这应该是可用的

    感谢您的帮助和有趣的讨论

    private decimal RandomDecimalRange01()
    {
        // 96 bits of random data; we'll use 94 bits to directly map decimal's max precision 0..1 range
        byte[] data = new byte[12];
        decimal value = 0;
    
        // loop until valid value is generated, discarding invalids values. Mostly controlled by top 2 bits: 11 is always invalid, 00 or 01, is always valid, 10 has valid and invalid ranges. Odds make loop generally find value in one or a few iterations.
        while (true)
        {
            // Acquire random bytes from random source (like TRNG device or CSPRNG api)
            if (!trng.GetBytes(data))
            {
                throw new Exception("Failed to aquire random bytes from source");
            }
            else
            {
                // Read 94 random bits (pull 96 bits, discard 2)
                BinaryReader reader = new BinaryReader(new MemoryStream(data));
                int low = reader.ReadInt32();
                int mid = reader.ReadInt32();
                int high = reader.ReadInt32() & 0x3FFFFFFF; // don't consume upper 2 random bits - out of range
    
                // Discard invalid values and reloop (interpret special invalid value as 1)
                if (high > 542101086)
                {
                    continue;
                }
                else if (high == 542101086)
                {
                    if (mid > 1042612833)
                    {
                        continue;
                    }
                    else if (mid == 1042612833)
                    {
                        if (low > 268435455)
                        {
                            // Special override to generate 1 value for inclusive [0..1] range - interpret the smallest invalid value as 1. Remove code for exclusive range [0..1)
                            if (low == 268435456)
                            {
                                value = 1m; // return 1.0
                                break;
                            }
                            continue;
                        }
                    }
                }
    
                // return random decimal created from parts - positive, maximum precision 28 (1C) scale
                value = new decimal(low, mid, high, false, 28);
                break;
            }
        }
        return value;
    }
    
    通过算法运行TrueRNGPro TRNG设备字节的示例生成值

    0.8086691474438979082567747041
    0.4268035919422123276460607186
    0.7758625805098585303332549015
    0.0701321080502462116399370731
    0.3127190777525873850928167447
    0.6022236739048965325585049764
    0.1244605652187291191393036867
    
    关于有趣边界值的测试

    // test databyte values for max & min ranges
    new byte[] { 0x01, 0x00, 0x00, 0x10, 0x61, 0x02, 0x25, 0x3E, 0x5E, 0xCE, 0x4F, 0x20 }; // boundary: 1 too large for algorithm, will be discarded
    new byte[] { 0x00, 0x00, 0x00, 0x10, 0x61, 0x02, 0x25, 0x3E, 0x5E, 0xCE, 0x4F, 0x20 }; // boundary: special 1 more than largest valid .99999..., interpret as 1 value
    new byte[] { 0xFF, 0xFF, 0xFF, 0x0F, 0x61, 0x02, 0x25, 0x3E, 0x5E, 0xCE, 0x4F, 0x20 }; // boundary: largest valid value .9999...
    new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // boundary: smallest valid value, should be 0
    new byte[] { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // boundary: 1 more than smallest valid value, should be .000...1
    

    十进制数的二进制表示法由1位组成 符号、96位整数和用于分割 整数,并指定其小数部分。 比例因子隐式地是数字10,提升为指数 从0到28

    返回值是一个由32位有符号整数组成的四元素数组

    返回数组的第一、第二和第三个元素包含 96位整数的低、中、高32位

    返回数组的第四个元素包含比例因子和 签名它由以下部分组成:

    位0至15(低位字)未使用,必须为零

    位16至23必须包含介于0和28之间的指数,即 表示10除以整数的幂

    位24至30未使用,必须为零

    位31包含符号:0表示正,1表示负

    您正在从中查找0

    十进制数的二进制表示法由1位组成 符号、96位整数和用于分割 整数,并指定其小数部分。 比例因子隐式地是数字10,提升为指数 从0到28

    返回值是一个由32位有符号整数组成的四元素数组

    返回数组的第一、第二和第三个元素包含 96位整数的低、中、高32位

    返回数组的第四个元素包含比例因子和 签名它由以下部分组成:

    位0至15(低位字)未使用,必须为零

    位16至23必须包含介于0和28之间的指数,即 表示10除以整数的幂

    位24至30未使用,必须为零

    位31包含符号:0表示正,1表示负

    您正在寻找0
    • 是否要在0和1(包括两端)之间均匀分布
    • 原始数据在字节级别是否也是统一的
    • 你到底需要多高的精确度
    • 您需要十进制还是浮点/双精度
    若你们使用十进制,我认为你们不会得到统一的分布,因为你们不能使用所有字节的整个范围

    对于浮点数,我认为如果你创建一个介于1和2之间的数字,然后减去1,可能更容易进行位操作。但是,您永远不会得到精确的1.0。

    • 是否要在0和1(包括两端)之间均匀分布
    • 原始数据在字节级别是否也是统一的
    • 你到底需要多高的精确度
    • 您需要十进制还是浮点/双精度
    若你们使用十进制,我认为你们不会得到统一的分布,因为你们不能使用所有字节的整个范围


    对于浮点数,我认为如果你创建一个介于1和2之间的数字,然后减去1,可能更容易进行位操作。但是,您永远不会得到精确的1.0。

    ReadUInt64()/Math.Pow(2,64)。如果你想吞下更多的字节,很难想象这是必要的,那么就使用biginger。这就是我开始的,这当然是一个实用的答案。但是在理论上(我没有测量过),除法比直接加载慢,而且96位十进制比64位整数有更多的状态可用。对,这只是一个理论。它有来自处理器的硬件支持,十进制类型没有,并且都是在软件中完成的。我做了一些测试;二进制加载到十进制的速度大约是ReadUInt64()/(decimal)ulong.MaxValue的两倍。正如你所说的,这并不是一个太大的惊喜,因为软件的分裂。我还尝试了IEEE双除法和浮点除法;double和十进制除法差不多,只是快了一点。Float更接近原始二进制加载。但我不知道我通过IEEE类型引入了什么偏见。所以我仍然需要将无偏值限制压缩到t中
    for (int exponent=0; exponent<=28; exponent++) {
        BigInteger max = BigInteger.Pow(10, exponent);
        for (int i = 0; i <= max; i++) {
            var fmt = "96bitinteger: {0}, exponent: {1}";
            Console.WriteLine(String.Format(fmt, i, exponent));
        }
    }
    
    int[] data = new int[] { 0x10000000, 0x3e250261, 0x204fce5e, 0x1C0000 };
    var random_data = data.SelectMany(BitConverter.GetBytes).ToArray();
    decimal value = new BinaryReader(new MemoryStream(random_data)).ReadDecimal();
    Console.WriteLine(value);
    
    if c < 0x204fce5e:
        a can be anything
        b can be anything
    elif c = 0x204fce5e:
        if b < 0x3e250261:
            a can be anything
        elif b = 0x3e250261
            constrain a <= 10000000
        b can not be greater than 0x3e250261
    c can not be greater than 0x204fce5e.