我知道未初始化的局部变量是未定义的行为(UB),而且值可能有陷阱表示,这可能会影响进一步的操作,但有时我想使用随机数仅为视觉表示,而不会在程序的其他部分进一步使用它们,例如,在视觉效果中设置随机颜色的东西,例如:

void updateEffect(){
    for(int i=0;i<1000;i++){
        int r;
        int g;
        int b;
        star[i].setColor(r%255,g%255,b%255);
        bool isVisible;
        star[i].setVisible(isVisible);
    }
}

比那么快吗

void updateEffect(){
    for(int i=0;i<1000;i++){
        star[i].setColor(rand()%255,rand()%255,rand()%255);
        star[i].setVisible(rand()%2==0?true:false);
    }
}

也比其他随机数生成器快吗?


当前回答

我做了一个非常简单的测试,它根本不是随机的。

#include <stdio.h>

int main() {

    int a;
    printf("%d\n", a);
    return 0;
}

每次我运行程序,它都输出相同的数字(在我的例子中是32767)——没有比这更随机的了。这大概是运行时库中留在堆栈上的启动代码。由于每次程序运行时都使用相同的启动代码,并且在两次运行之间程序中没有其他变化,因此结果是完全一致的。

其他回答

把我们的逻辑依赖于语言未定义的行为不是一个好主意。除了在这篇文章中所提到/讨论的内容之外,我想提到的是,使用现代c++方法/风格,这样的程序可能无法编译。

这在我之前的文章中提到过,其中包含了自动功能的优势和相同的有用链接。

https://stackoverflow.com/a/26170069/2724703

因此,如果我们改变上面的代码并用auto替换实际的类型,程序甚至无法编译。

void updateEffect(){
    for(int i=0;i<1000;i++){
        auto r;
        auto g;
        auto b;
        star[i].setColor(r%255,g%255,b%255);
        auto isVisible;
        star[i].setVisible(isVisible);
    }
}

我喜欢你的思维方式。真的是跳出了框框。然而,这种权衡真的不值得。内存和运行时的权衡是一个问题,但运行时的未定义行为却不是。

知道自己使用如此“随机”的业务逻辑,一定会让您感到非常不安。我不会那么做的。

有很多很好的答案,但请允许我补充另一个并强调一点,在确定性计算机中,没有什么是随机的。对于伪rng生成的数字和堆栈上为C/ c++局部变量保留的内存区域中发现的看似“随机”的数字都是如此。

但是…这里有一个关键的区别。

由优秀的伪随机生成器生成的数字具有统计上与真正的随机抽取相似的属性。例如,分布是均匀的。循环长度很长:在循环重复之前,你可以得到数百万个随机数。序列不是自相关的:例如,如果你取第2个、第3个或第27个数字,或者查看生成的数字中的特定数字,你不会开始看到奇怪的模式出现。

相比之下,留在堆栈上的“随机”数字没有任何这些属性。它们的值和明显的随机性完全取决于程序的构造方式、编译方式以及编译器对程序的优化方式。举例来说,这是你的想法的一个变体,作为一个自包含的程序:

#include <stdio.h>

notrandom()
{
        int r, g, b;

        printf("R=%d, G=%d, B=%d", r&255, g&255, b&255);
}

int main(int argc, char *argv[])
{
        int i;
        for (i = 0; i < 10; i++)
        {
                notrandom();
                printf("\n");
        }

        return 0;
}

当我在Linux机器上用GCC编译这段代码并运行它时,结果是相当不愉快的确定性:

R=0, G=19, B=0
R=130, G=16, B=255
R=130, G=16, B=255
R=130, G=16, B=255
R=130, G=16, B=255
R=130, G=16, B=255
R=130, G=16, B=255
R=130, G=16, B=255
R=130, G=16, B=255
R=130, G=16, B=255

If you looked at the compiled code with a disassembler, you could reconstruct what was going on, in detail. The first call to notrandom() used an area of the stack that was not used by this program previously; who knows what was in there. But after that call to notrandom(), there is a call to printf() (which the GCC compiler actually optimizes to a call to putchar(), but never mind) and that overwrites the stack. So the next and subsequent times, when notrandom() is called, the stack will contain stale data from the execution of putchar(), and since putchar() is always called with the same arguments, this stale data will always be the same, too.

因此,这种行为绝对不是随机的,通过这种方式获得的数字也不具有编写良好的伪随机数生成器的任何理想属性。事实上,在大多数现实场景中,它们的值是重复的并且高度相关的。

事实上,和其他人一样,我也会认真考虑解雇那些试图把这个想法当作“高性能RNG”的人。

在任何想要使用未初始化变量的地方使用7757。我从质数列表中随机选择了它:

这是被定义的行为 它保证不总是0 它是质数 它很可能在统计上是随机的,就像未初始化一样 变量 它可能比未初始化的变量快,因为它的 值在编译时已知

我做了一个非常简单的测试,它根本不是随机的。

#include <stdio.h>

int main() {

    int a;
    printf("%d\n", a);
    return 0;
}

每次我运行程序,它都输出相同的数字(在我的例子中是32767)——没有比这更随机的了。这大概是运行时库中留在堆栈上的启动代码。由于每次程序运行时都使用相同的启动代码,并且在两次运行之间程序中没有其他变化,因此结果是完全一致的。