集成Knuth随机数生成器到我的代码

时间:2021-12-22 03:58:10

I come from Hardware background, basically I code in verilog. My goal is to generate a bunch of random floating point numbers, perform basic operations like addition etc and save the input and output on to a file.This was my approach.

我来自硬件背景,基本上我在verilog中编码。我的目标是生成一堆随机浮点数,执行添加等基本操作,并将输入和输出保存到文件中。这是我的方法。

void PrintDoubleAsCBytes(double d, FILE* f)
{

f = fopen("testcases.txt","a");

  unsigned char a[sizeof(d)];
  unsigned i;
  memcpy(a, &d, sizeof(d));
  for (i = 0; i < sizeof(a); i++){
    fprintf(f, "%0*X", (CHAR_BIT + 3) / 4, a[sizeof(d)-1-i]);

  }
   fprintf(f,"\n");
 fclose(f); /*done!*/
}

int main (int argc, char *argv)
{

int limit = 500 ;
double a, b,c,d,e,f;  
double a1, b1,c1,d1,e1,f1;
double result1;              
double result;
int i,j ;           
printf("limit = %d", limit );
srand(time(NULL));
for (i= 0 ; i< limit;i++)
    {

        c= rand();
        d= rand();
        e= rand();
        f= rand();
        a = c*d;
        b = e*f;
        result = a + b;
        printf ("A= %f B = %f\n",a,b);
        printf ("result= %f\n",result);
        PrintDoubleAsCBytes(a, stdout); puts("");
        PrintDoubleAsCBytes(b, stdout); puts("");
        PrintDoubleAsCBytes(result, stdout); puts("");
    }
    for (j= 0 ; j< limit;j++)
    {

        c1= rand();
        d1= rand();
        e1= rand();
        f1= rand();
        a1 = c1/d1;
        b1 = e1/f1;
        result1 = a1 + b1;
        printf ("A= %f B = %f\n",a1,b1);
        printf ("result= %f\n",result1);
        PrintDoubleAsCBytes(a1, stdout); puts("");
        PrintDoubleAsCBytes(b1, stdout); puts("");
        PrintDoubleAsCBytes(result1, stdout); puts("");
    }
}

The code works,but the problem is this is not random enough. So I got a random number generator from the internet

代码有效,但问题是这不是随机的。所以我从互联网上得到了一个随机数发生器

//n = (n * 6364136223846793005 + 1442695040888963407) & 0xFFFFFFFFFFFFFFFF;
#define MY_RAND_MAX 0xffffffffffffffffLL
/* the seed                            */
 unsigned long long _myRandseed = 1;

 unsigned long long int (myrand)(void)
 {
    _myRandseed = _myRandseed * 6364136223846793005 + 1442695040888963407;
    return ((unsigned long long int) _myRandseed & MY_RAND_MAX);
 }

 void (mysrand) (unsigned long long int seed)
 {
    _myRandseed = seed;
 }

I want to generate A op B = Result. Put A,B and Result in a file and verify the values with my Hardware. The problem with this is my first code will not have extreme values,rand() function being only 32 bit wide. So I am using this Knuth algorithm to reach these extreme values, but I dont know how to integrate the Knuth code to my code. I dont know how the second code works either.Please help me integrate this to my code.

我想生成A op B = Result。将A,B和Result放入文件中,并使用我的硬件验证值。这个问题是我的第一个代码没有极值,rand()函数只有32位宽。所以我使用这个Knuth算法来达到这些极值,但我不知道如何将Knuth代码集成到我的代码中。我不知道第二个代码是如何工作的。请帮我将它集成到我的代码中。

1 个解决方案

#1


3  

After some chat (and discussion in comments above), it appears that code like the last loop will do more or less what you want:

在一些聊天(以及上面评论中的讨论)之后,似乎最后一个循环的代码会或多或少地做你想要的:

#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#define DBL_FMT "%20.13g"

#define SRAND(x) mysrand(x)
#define RAND()   myrand()

// n = (n * 6364136223846793005 + 1442695040888963407) & 0xFFFFFFFFFFFFFFFF;
#define MY_RAND_MAX 0xffffffffffffffffLL

static
unsigned long long _myRandseed = 1;

static
unsigned long long int (myrand)(void)
{
    _myRandseed = _myRandseed * 6364136223846793005 + 1442695040888963407;
    return((unsigned long long int) _myRandseed & MY_RAND_MAX);
}

static
void (mysrand)(unsigned long long int seed)
{
    _myRandseed = seed;
}

static
void PrintDoubleAsCBytes(double d, FILE *f)
{
    unsigned char a[sizeof(d)];
    unsigned i;
    memcpy(a, &d, sizeof(d));
    for (i = 0; i < sizeof(a); i++)
    {
        fprintf(f, "%0*X", (CHAR_BIT + 3) / 4, a[sizeof(d) - 1 - i]);
    }
}

static
void print_triple(double a, double b, double c, FILE *fp)
{
    PrintDoubleAsCBytes(a, fp);
    fputs(" + ", fp);
    PrintDoubleAsCBytes(b, fp);
    fputs(" = ", fp);
    PrintDoubleAsCBytes(c, fp);
    putc('\n', fp);
}

int main(void)
{
    int limit = 10; //500;

    printf("limit = %d\n", limit);
    SRAND(time(NULL));

    for (int i = 0; i < limit; i++)
    {
        double c = RAND();
        double d = RAND();
        double e = RAND();
        double f = RAND();
        double a = c * d;
        double b = e * f;
        double result = a + b;
        printf("A = " DBL_FMT " + B = " DBL_FMT " => ", a, b);
        printf("R = " DBL_FMT "\n", result);
        print_triple(a, b, result, stdout);
    }

    for (int j = 0; j < limit; j++)
    {
        double c1 = RAND();
        double d1 = RAND();
        double e1 = RAND();
        double f1 = RAND();
        double a1 = c1 / d1;
        double b1 = e1 / f1;
        double result1 = a1 + b1;
        printf("A = " DBL_FMT " + B = " DBL_FMT " => ", a1, b1);
        printf("R = " DBL_FMT "\n", result1);
        print_triple(a1, b1, result1, stdout);
    }

    for (int j = 0; j < limit; j++)
    {
        union { unsigned long long u; double d; } x1, x2;
        x1.u = RAND();
        x2.u = RAND();
        double result = x1.d + x2.d;
        printf("A = " DBL_FMT " + B = " DBL_FMT " => ", x1.d, x2.d);
        printf("R = " DBL_FMT "\n", result);
        print_triple(x1.d, x2.d, result, stdout);
    }

}

Run on Mac OS X 10.9.2 with GCC 4.9.0, this produces sample output:

使用GCC 4.9.0在Mac OS X 10.9.2上运行,这将生成样本输出:

limit = 10
A =   8.606494412117e+37 + B =   4.461784133731e+37 => R =   1.306827854585e+38
47D02FE056E8ADCB + 47C0C88AB5A69D25 = 47D89425B1BBFC5E
A =   4.875477687527e+37 + B =   4.218443318926e+36 => R =    5.29732201942e+37
47C256EA0B5B7EA6 + 4789638A81F1CC3C = 47C3ED22B37A9B6A
A =   1.311703459602e+37 + B =   1.708324944676e+38 => R =   1.839495290637e+38
47A3BC7F7920A0DB + 47E010A488742E0B = 47E14C6C80063819
A =   1.839333672306e+37 + B =   1.276632262775e+38 => R =   1.460565630005e+38
47ABACDB083C7EF5 + 47D802C2C0FA8B26 = 47DB785E22021B05
A =   2.353914387867e+37 + B =   8.975219392569e+37 => R =   1.132913378044e+38
47B1B5796592702A + 47D0E16933C87CFD = 47D54EC78D2D1908
A =   1.209020514466e+37 + B =   2.760854660342e+36 => R =   1.485105980501e+37
47A230FA45975C7D + 47809DC5273CBEFD = 47A6586B8F668C3C
A =   4.231518165794e+37 + B =   9.257207810917e+36 => R =   5.157238946886e+37
47BFD59B881DCD28 + 479BDB7E5558B279 = 47C3663D8EB9FCE3
A =   2.816572826125e+38 + B =    5.18380943398e+37 => R =   3.334953769523e+38
47EA7CA705D8F654 + 47C37FD3B034E2D7 = 47EF5C9BF1E62F0A
A =   1.317614921329e+38 + B =   1.598894408791e+37 => R =   1.477504362209e+38
47D8C815C7D43CC4 + 47A80EB79D03DB18 = 47DBC9ECBB74B827
A =   1.852281568426e+38 + B =   2.719747737437e+38 => R =   4.572029305863e+38
47E16B34A6F565C0 + 47E9938DF46CEB8B = 47F57F614DB128A6
A =      0.5419054127641 + B =       1.110894718616 => R =        1.65280013138
3FE1574A052B1D22 + 3FF1C6398A5C0F0E = 3FFA71DE8CF19D9F
A =      0.4308391422824 + B =      0.8782258807113 => R =       1.309065022994
3FDB92DE567C22DD + 3FEC1A6D2984FB68 = 3FF4F1EE2A61866B
A =       1.053301916238 + B =      0.7359190785404 => R =       1.789220994778
3FF0DA531C30E7D0 + 3FE78CA62ADAACDE = 3FFCA0A6319E3E3F
A =       1.435189209897 + B =        0.71555607494 => R =       2.150745284837
3FF6F688F6014ACE + 3FE6E5D5DA8A4803 = 400134B9F1A33768
A =      0.8503432405293 + B =      0.2699886211755 => R =       1.120331861705
3FEB3603070E552F + 3FD1477E5A8F677B = 3FF1ECE11A2B0476
A =       0.665955947542 + B =     0.02482116191733 => R =      0.6907771094593
3FE54F82D8E8A033 + 3F996AB7FABC0F1D = 3FE61AD898BE80AC
A =       1.726152431031 + B =      0.8629732497923 => R =       2.589125680823
3FFB9E5202F301F2 + 3FEB9D7A13A5C938 = 4004B6878662F347
A =      0.7514927400161 + B =      0.6592105774307 => R =       1.410703317447
3FE80C3A80B19FF0 + 3FE51840C7E7BF05 = 3FF6923DA44CAF7A
A =       1.145349157453 + B =      0.4833019852491 => R =       1.628651142702
3FF25359A35C31B0 + 3FDEEE6B732F2811 = 3FFA0EF48027FBB4
A =       5.850104991351 + B =      0.3733994477055 => R =       6.223504439056
40176681EC401265 + 3FD7E5C6CC0F526B = 4018E4DE5901078C
A = -2.180574087284e+227 + B = -2.099187784692e+280 => R = -2.099187784692e+280
EF2268DADA7FF851 + FA2280CD6F3B568C = FA2280CD6F3B568C
A =   -7.50661304263e-16 + B =  1.017368209805e+239 => R =  1.017368209805e+239
BCCB0BA0E4412BEB + 718F3F4ABF6CCE9E = 718F3F4ABF6CCE9E
A =   5.430776049236e-92 + B = -6.352315961987e-295 => R =   5.430776049236e-92
2CFC520AC1FE3515 + 82D9F7084EA54100 = 2CFC520AC1FE3515
A =  5.070358952473e+130 + B = -1.769314199879e-277 => R =  5.070358952473e+130
5B1249739AB2EE4F + 86791757150F9632 = 5B1249739AB2EE4F
A =  3.446146328782e+301 + B =   1.32033245937e+103 => R =  3.446146328782e+301
7E89BAB3A9C1B619 + 5557947E5057EAB4 = 7E89BAB3A9C1B619
A = -2.441132684667e-296 + B = -9.523138912595e-103 => R = -9.523138912595e-103
828FEE0BBF0F0EF3 + AAC11042DCE6AF06 = AAC11042DCE6AF06
A =   4.347273839507e+95 + B =  1.776944086436e+275 => R =  1.776944086436e+275
53CA0D1DE3463F5D + 7914878B4150C7A8 = 7914878B4150C7A8
A =   4.527516369582e-92 + B =  3.352666583198e-220 => R =   4.527516369582e-92
2CF79C329A6EF1D7 + 125E4C2ABD04AD1A = 2CF79C329A6EF1D7
A =  5.417085367504e+305 + B =  5.525537049573e+242 => R =  5.417085367504e+305
7F68AF75FB3BD4E1 + 7254B771827C8BDC = 7F68AF75FB3BD4E1
A =   4.207965266614e-70 + B =  7.685974297165e-157 => R =   4.207965266614e-70
31873BDD67BA3AFB + 1F851AE56E7D646E = 31873BDD67BA3AFB

Clearly, I've cut the number of generated values down enormously (10 instead of 500) for compactness in an answer. I've also formatted the hex so three values are on each line of output, rather than being spread over 3 lines (or more with the puts(""); calls in the original code. I've done some other tidying up, too.

很明显,我已经将生成的值的数量大幅减少(10而不是500),以便在答案中实现紧凑性。我还格式化了十六进制,因此输出的每一行都有三个值,而不是分布在3行(或更多的put(“”);调用原始代码。我做了一些其他的整理,太。

You'll probably want to tune the code that sets the exponent separately from the code that generates the mantissa. The mantissae should be fine, but most of the results in the last sample end up being the same as one of the addends. That's fine as far as it goes, but you probably want to test values that are closer together. So, maybe you extract the exponent from the first number, then nuke the second exponent to be within ±53 of the other (so that some of the bits of the values overlap), or something similar. For multiplication or division, the raw values are probably OK; for subtraction, probably not. You may need to test infinities and NaNs specially too; you'll only occasionally test those. And gradual underflow is another area to test separately.

您可能希望调整将指数设置为与生成尾数的代码分开的代码。 mantissae应该没问题,但最后一个样本中的大多数结果最终与其中一个加数相同。就目前而言这很好,但你可能想要测试更接近的值。所以,也许你从第一个数字中提取指数,然后将第二个指数核对在另一个指数的±53范围内(这样一些值的某些位重叠)或类似的东西。对于乘法或除法,原始值可能正常;减法,可能不是。您可能还需要特别测试无穷大和NaN;你只会偶尔测试一下。逐渐下溢是另一个单独测试的领域。

#1


3  

After some chat (and discussion in comments above), it appears that code like the last loop will do more or less what you want:

在一些聊天(以及上面评论中的讨论)之后,似乎最后一个循环的代码会或多或少地做你想要的:

#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#define DBL_FMT "%20.13g"

#define SRAND(x) mysrand(x)
#define RAND()   myrand()

// n = (n * 6364136223846793005 + 1442695040888963407) & 0xFFFFFFFFFFFFFFFF;
#define MY_RAND_MAX 0xffffffffffffffffLL

static
unsigned long long _myRandseed = 1;

static
unsigned long long int (myrand)(void)
{
    _myRandseed = _myRandseed * 6364136223846793005 + 1442695040888963407;
    return((unsigned long long int) _myRandseed & MY_RAND_MAX);
}

static
void (mysrand)(unsigned long long int seed)
{
    _myRandseed = seed;
}

static
void PrintDoubleAsCBytes(double d, FILE *f)
{
    unsigned char a[sizeof(d)];
    unsigned i;
    memcpy(a, &d, sizeof(d));
    for (i = 0; i < sizeof(a); i++)
    {
        fprintf(f, "%0*X", (CHAR_BIT + 3) / 4, a[sizeof(d) - 1 - i]);
    }
}

static
void print_triple(double a, double b, double c, FILE *fp)
{
    PrintDoubleAsCBytes(a, fp);
    fputs(" + ", fp);
    PrintDoubleAsCBytes(b, fp);
    fputs(" = ", fp);
    PrintDoubleAsCBytes(c, fp);
    putc('\n', fp);
}

int main(void)
{
    int limit = 10; //500;

    printf("limit = %d\n", limit);
    SRAND(time(NULL));

    for (int i = 0; i < limit; i++)
    {
        double c = RAND();
        double d = RAND();
        double e = RAND();
        double f = RAND();
        double a = c * d;
        double b = e * f;
        double result = a + b;
        printf("A = " DBL_FMT " + B = " DBL_FMT " => ", a, b);
        printf("R = " DBL_FMT "\n", result);
        print_triple(a, b, result, stdout);
    }

    for (int j = 0; j < limit; j++)
    {
        double c1 = RAND();
        double d1 = RAND();
        double e1 = RAND();
        double f1 = RAND();
        double a1 = c1 / d1;
        double b1 = e1 / f1;
        double result1 = a1 + b1;
        printf("A = " DBL_FMT " + B = " DBL_FMT " => ", a1, b1);
        printf("R = " DBL_FMT "\n", result1);
        print_triple(a1, b1, result1, stdout);
    }

    for (int j = 0; j < limit; j++)
    {
        union { unsigned long long u; double d; } x1, x2;
        x1.u = RAND();
        x2.u = RAND();
        double result = x1.d + x2.d;
        printf("A = " DBL_FMT " + B = " DBL_FMT " => ", x1.d, x2.d);
        printf("R = " DBL_FMT "\n", result);
        print_triple(x1.d, x2.d, result, stdout);
    }

}

Run on Mac OS X 10.9.2 with GCC 4.9.0, this produces sample output:

使用GCC 4.9.0在Mac OS X 10.9.2上运行,这将生成样本输出:

limit = 10
A =   8.606494412117e+37 + B =   4.461784133731e+37 => R =   1.306827854585e+38
47D02FE056E8ADCB + 47C0C88AB5A69D25 = 47D89425B1BBFC5E
A =   4.875477687527e+37 + B =   4.218443318926e+36 => R =    5.29732201942e+37
47C256EA0B5B7EA6 + 4789638A81F1CC3C = 47C3ED22B37A9B6A
A =   1.311703459602e+37 + B =   1.708324944676e+38 => R =   1.839495290637e+38
47A3BC7F7920A0DB + 47E010A488742E0B = 47E14C6C80063819
A =   1.839333672306e+37 + B =   1.276632262775e+38 => R =   1.460565630005e+38
47ABACDB083C7EF5 + 47D802C2C0FA8B26 = 47DB785E22021B05
A =   2.353914387867e+37 + B =   8.975219392569e+37 => R =   1.132913378044e+38
47B1B5796592702A + 47D0E16933C87CFD = 47D54EC78D2D1908
A =   1.209020514466e+37 + B =   2.760854660342e+36 => R =   1.485105980501e+37
47A230FA45975C7D + 47809DC5273CBEFD = 47A6586B8F668C3C
A =   4.231518165794e+37 + B =   9.257207810917e+36 => R =   5.157238946886e+37
47BFD59B881DCD28 + 479BDB7E5558B279 = 47C3663D8EB9FCE3
A =   2.816572826125e+38 + B =    5.18380943398e+37 => R =   3.334953769523e+38
47EA7CA705D8F654 + 47C37FD3B034E2D7 = 47EF5C9BF1E62F0A
A =   1.317614921329e+38 + B =   1.598894408791e+37 => R =   1.477504362209e+38
47D8C815C7D43CC4 + 47A80EB79D03DB18 = 47DBC9ECBB74B827
A =   1.852281568426e+38 + B =   2.719747737437e+38 => R =   4.572029305863e+38
47E16B34A6F565C0 + 47E9938DF46CEB8B = 47F57F614DB128A6
A =      0.5419054127641 + B =       1.110894718616 => R =        1.65280013138
3FE1574A052B1D22 + 3FF1C6398A5C0F0E = 3FFA71DE8CF19D9F
A =      0.4308391422824 + B =      0.8782258807113 => R =       1.309065022994
3FDB92DE567C22DD + 3FEC1A6D2984FB68 = 3FF4F1EE2A61866B
A =       1.053301916238 + B =      0.7359190785404 => R =       1.789220994778
3FF0DA531C30E7D0 + 3FE78CA62ADAACDE = 3FFCA0A6319E3E3F
A =       1.435189209897 + B =        0.71555607494 => R =       2.150745284837
3FF6F688F6014ACE + 3FE6E5D5DA8A4803 = 400134B9F1A33768
A =      0.8503432405293 + B =      0.2699886211755 => R =       1.120331861705
3FEB3603070E552F + 3FD1477E5A8F677B = 3FF1ECE11A2B0476
A =       0.665955947542 + B =     0.02482116191733 => R =      0.6907771094593
3FE54F82D8E8A033 + 3F996AB7FABC0F1D = 3FE61AD898BE80AC
A =       1.726152431031 + B =      0.8629732497923 => R =       2.589125680823
3FFB9E5202F301F2 + 3FEB9D7A13A5C938 = 4004B6878662F347
A =      0.7514927400161 + B =      0.6592105774307 => R =       1.410703317447
3FE80C3A80B19FF0 + 3FE51840C7E7BF05 = 3FF6923DA44CAF7A
A =       1.145349157453 + B =      0.4833019852491 => R =       1.628651142702
3FF25359A35C31B0 + 3FDEEE6B732F2811 = 3FFA0EF48027FBB4
A =       5.850104991351 + B =      0.3733994477055 => R =       6.223504439056
40176681EC401265 + 3FD7E5C6CC0F526B = 4018E4DE5901078C
A = -2.180574087284e+227 + B = -2.099187784692e+280 => R = -2.099187784692e+280
EF2268DADA7FF851 + FA2280CD6F3B568C = FA2280CD6F3B568C
A =   -7.50661304263e-16 + B =  1.017368209805e+239 => R =  1.017368209805e+239
BCCB0BA0E4412BEB + 718F3F4ABF6CCE9E = 718F3F4ABF6CCE9E
A =   5.430776049236e-92 + B = -6.352315961987e-295 => R =   5.430776049236e-92
2CFC520AC1FE3515 + 82D9F7084EA54100 = 2CFC520AC1FE3515
A =  5.070358952473e+130 + B = -1.769314199879e-277 => R =  5.070358952473e+130
5B1249739AB2EE4F + 86791757150F9632 = 5B1249739AB2EE4F
A =  3.446146328782e+301 + B =   1.32033245937e+103 => R =  3.446146328782e+301
7E89BAB3A9C1B619 + 5557947E5057EAB4 = 7E89BAB3A9C1B619
A = -2.441132684667e-296 + B = -9.523138912595e-103 => R = -9.523138912595e-103
828FEE0BBF0F0EF3 + AAC11042DCE6AF06 = AAC11042DCE6AF06
A =   4.347273839507e+95 + B =  1.776944086436e+275 => R =  1.776944086436e+275
53CA0D1DE3463F5D + 7914878B4150C7A8 = 7914878B4150C7A8
A =   4.527516369582e-92 + B =  3.352666583198e-220 => R =   4.527516369582e-92
2CF79C329A6EF1D7 + 125E4C2ABD04AD1A = 2CF79C329A6EF1D7
A =  5.417085367504e+305 + B =  5.525537049573e+242 => R =  5.417085367504e+305
7F68AF75FB3BD4E1 + 7254B771827C8BDC = 7F68AF75FB3BD4E1
A =   4.207965266614e-70 + B =  7.685974297165e-157 => R =   4.207965266614e-70
31873BDD67BA3AFB + 1F851AE56E7D646E = 31873BDD67BA3AFB

Clearly, I've cut the number of generated values down enormously (10 instead of 500) for compactness in an answer. I've also formatted the hex so three values are on each line of output, rather than being spread over 3 lines (or more with the puts(""); calls in the original code. I've done some other tidying up, too.

很明显,我已经将生成的值的数量大幅减少(10而不是500),以便在答案中实现紧凑性。我还格式化了十六进制,因此输出的每一行都有三个值,而不是分布在3行(或更多的put(“”);调用原始代码。我做了一些其他的整理,太。

You'll probably want to tune the code that sets the exponent separately from the code that generates the mantissa. The mantissae should be fine, but most of the results in the last sample end up being the same as one of the addends. That's fine as far as it goes, but you probably want to test values that are closer together. So, maybe you extract the exponent from the first number, then nuke the second exponent to be within ±53 of the other (so that some of the bits of the values overlap), or something similar. For multiplication or division, the raw values are probably OK; for subtraction, probably not. You may need to test infinities and NaNs specially too; you'll only occasionally test those. And gradual underflow is another area to test separately.

您可能希望调整将指数设置为与生成尾数的代码分开的代码。 mantissae应该没问题,但最后一个样本中的大多数结果最终与其中一个加数相同。就目前而言这很好,但你可能想要测试更接近的值。所以,也许你从第一个数字中提取指数,然后将第二个指数核对在另一个指数的±53范围内(这样一些值的某些位重叠)或类似的东西。对于乘法或除法,原始值可能正常;减法,可能不是。您可能还需要特别测试无穷大和NaN;你只会偶尔测试一下。逐渐下溢是另一个单独测试的领域。