zoukankan      html  css  js  c++  java
  • 随机以及时间相关函数——C语言描述

    随机相关的函数

      头文件 stdlib.h

      相关函数 :rand 、srand

      rand( rand C++ Reference )

      函数声明:int rand( void );

      rand函数返回一个位于 0 - RAND_MAX之间的伪随机整数。其中RAND_MAX在头文件 stdlib.h 中定义( 一般为int类型可表示的最大正整数 )。

      rand函数通过一个特定的随机数生成算法生成伪随机数序列,该算法依据一个初始的种子值进行伪随机数生成。伪随机数生成可以看做一个特殊的处理过程,对于同一个输入(种子),输出的伪随机值序列总是相同的( 相对于一次程序运行 )。可使用函数 srand 设置伪随机数算法的种子,rand函数默认的种子值为1。

      srand( srand C++ Reference )

      函数声明: void srand( unsigned int seed);

      初始化伪随机序列生成器的种子值。srand函数将伪随机数生成算法的种子使用参数 seed 初始化,使得伪随机数生成依赖于不同的种子,避免重复。通过将种子值 seed 设置为不同的可区分的值(如程序运行时的时间),可以保证生成的伪随机序列较为随机。

      seed = 1时,即为伪随机序列生成算法的默认初始初始值。

      示例:

    #include<stdio.h>
    #include<stdlib.h>
    
    #define num_of_loop 8                   /*循环次数*/   
    void generate_random_num(void);         /*产生随机序列并输出*/
    
    int main(void)
    {
        generate_random_num();              /*使用默认的随机种子,即 1*/
    
        srand( 5 );                         /*使用 5 初始化随机种子*/
        generate_random_num();
    
        srand( 1 );                         /*使用 1 初始化随机种子*/
        generate_random_num();
    
        return 0;
    }
    
    void generate_random_num(void)
    {
        int i;
        for( i = 0 ; i < num_of_loop ; i++)
         printf("%d	",rand());
    
        printf("
    ");
    }                                                
    rand示例

      结果如下图:

      

       可以看到默认种子的随机序列和种子值为1的随机序列是一样的,而种子值为5的随机序列则不相同。事实上,对于同一个种子值,每次程序运行产生的随机序列都是一样的( 注意不是每次 rand 函数调用,而是每次程序运行 )。即下一次运行上述示例时,仍产生一样的伪随机序列。

      为了使得由固定种子值产生的固定伪随机序列是较为随机的,可以在每次运行程序或调用 rand 函数之前使用不同的种子值来进行初始化。常用的方法是使用在函数调用之时的时间来作为种子值。

    时间相关的函数

      头文件:time.h

      相关函数:time、clock

      time( time C++ Reference )

      函数声明:time_t time( time_t *timer );

      time函数的参数可以为空,即 0 / NULL ,此时 time 函数返回一个 time_t 类型的日历时间;

      time函数接受一个指向 time_t 类型变量的指针作为参数,函数返回一个 time_t 类型的日历时间,并将参数指针指向的变量值设置为该日历时间。

      time函数返回的日历时间精确到秒级。

      根据上文对随机函数的描述,我们可以使用下面的语句来对随机数序列的种子初始化,这样每次进行初始化时的种子在秒级别的精度上是不一样,故而可以做到较好的随机。

     srand( (int) time(NULL) )     //使用 time 函数返回的日历时间初始化函数,在秒级进度上保证每次种子值一致

      clock( clock C++ Reference )

      函数声明:clock_t clock( void );

      clock函数返回程序运行至clock函数处所消耗的处理器时间( 时间片数 ),若调用失败则返回 -1。

      clock函数返回值为运行消耗的时间片数,一个时间片为系统设置的一个常量时间单元,不同的系统时间片长度可能不同。可以通过在程序运行的不同位置设置两个clock函数,并根据其差值获得程序运行所消耗的时间片数。在头文件 time.h 中,存在宏定义 CLOCKS_PER_SEC,定义每秒所包含的时间片数。使用时可以通过 clock 函数得到消耗的时间片数,再通过除法获得具体消耗的秒数。

      

      其他函数:

      gmtime

      函数声明:struct tm* gmtime( const time_t  timer );

      将time_t 类型的值转换为UTC时间,并存放在一个 tm 类型的结构体中。

      

      localtime

      函数声明:struct tm* localtime( const time_t timer );

      将time_t类型的值转换为本地时间,并存放在一个 tm 类型的结构体中。

      

      actime

      函数声明:char * actime( const tm *timer);

      将 tm 结构体的数据转换为一个格式固定的字符串。

      

      结构体 tm ( 摘自头文件time.h )

    struct tm
    {
        int    tm_sec;     /* Seconds: 0-59 (K&R says 0-61?) */
        int    tm_min;     /* Minutes: 0-59 */
        int    tm_hour;    /* Hours since midnight: 0-23 */
        int    tm_mday;    /* Day of the month: 1-31 */
        int    tm_mon;     /* Months *since* january: 0-11 */
        int    tm_year;    /* Years since 1900 */
        int    tm_wday;    /* Days since Sunday (0-6) */
        int    tm_yday;    /* Days since Jan. 1: 0-365 */
        int    tm_isdst;   /* +1 Daylight Savings Time, 0 No DST,
                         /* -1 don't know */
    };

      可以看到,tm结构体记录了年 月 日 时 分 秒 等信息,可通过 asctime 函数转换为方便显示的字符串形式。

      示例: 

    display time
    #include<time.h>
    #include<stdio.h>
    
    int main(void)
    {
        char *local_time = NULL ;
        char *UTC_time = NULL ;
        struct tm *t_in_tm = NULL ;
    
    
        time_t t = time( NULL );
        t_in_tm = localtime( &t );          //将time_t类型的数值参数转换为tm结构体中保存(本地时间)
        local_time = asctime( t_in_tm );    //将tm类型结构体中的数值转换为字符串形式
        printf("local time is %s
    ",local_time);
    
        t_in_tm = gmtime( &t );             //将time_t类型的数值参数转换为tm结构体中保存(UTC时间)
        UTC_time = asctime( t_in_tm );      //将tm类型结构体中的数值转换为字符串形式
    
        printf("UTC time is %s
    ",UTC_time);
    
        return 0;
    }

      可以看到本地时间与UTC时间相差八个小时

      

      注意:可以从示例代码中看到,在程序运行过程中,并没有声明一个具体的 tm 类型的结构体和存放字符串的数组用于存放数据,而只是声明了用于指向这些结构的指针用于存放返回值。这是由于上述函数的操作是针对一个公用的静态缓冲区来进行的,返回的参数为指向该缓冲区内具体结构的指针,故而不需要使用者另行声明。

      在头文件time.h中有如下警告:

      

      也就是说上述静态缓冲区是由函数共享的,可能被其他函数覆盖数据,使用需要小心。

      实际上,笔者在书写示例代码时,首先书写的是如下程序(只保留核心部分,读者可以比较一下与上面示例的微小不同),结果输出的两个时间总是相同的,而不是相隔8个小时。

    1     time_t t = time( NULL );
    2     t_in_tm = localtime( &t );          //将time_t类型的数值参数转换为tm结构体中保存(本地时间)
    3     local_time = asctime( t_in_tm );    //将tm类型结构体中的数值转换为字符串形式
    4
    5     t_in_tm = gmtime( &t );             //将time_t类型的数值参数转换为tm结构体中保存(UTC时间)
    6     UTC_time = asctime( t_in_tm );      //将tm类型结构体中的数值转换为字符串形式
    7 
    8     printf("local time is %s
    UTC time is %s
    ",local_time,UTC_time);

      原因解释:在第一次函数调用返回( 2,3行),函数返回的是指向静态缓冲区中 tm 结构和字符串所在内存的地址。在第二次返回对应结构的内存地址指针时( 5,6行),由于公用静态缓冲区,后续 gmtime 和 asctime 函数使用的内存空间与 localtime 和 asctime使用的内存空间相同。即第二次操作是在同样的缓冲区中操作。结果就是,local_time和UTC_time指向的是同一片内存区域,且该区域最后一次是由第6行操作改变的,从而使的两个字符串输出的都是UTC时间形式。这也从侧面反应出共用静态缓冲区可能带来的弊端。

      更高精度的时间获取,可以参考博客 Windows获取当前系统时间

  • 相关阅读:
    RabbitMQ(dotnet基本使用)
    SignalR三种使用方式整理比较
    Asp.Net下SignalR的三种实现方式
    多种单例模式实现及区别
    VS/Xamarin Android开发Follow Me(十九)
    VS/Xamarin Android开发Follow Me(十八)
    比较大小的几种方法
    C# 求Π Π/4=1-1/3+1/5-1/7+......+1/(2*n-3)-1/(2*n-1); (n=2000)
    一步一步剖析Dictionary实现原理
    查看.net frameword版本
  • 原文地址:https://www.cnblogs.com/yhjoker/p/7877713.html
Copyright © 2011-2022 走看看