非确定性的来源

12

我的本应该是确定性程序在不同运行时会产生几个略有不同的输出。输入、编译器和计算机都没有改变。我不确定哪个输出是正确的,因为它们总是看起来合理。

除了偶然调用rand()函数之外,还可能出现什么问题呢?


7
在我们进行猜测之前,我们需要看到一些代码。 - Andy_Vulhop
2
你的代码中是否包含任何进入未定义行为领域的内容? - James McNellis
1
谁说编译器是确定性的? - AshleysBrain
@AshleysBrain - 请查看此问题https://dev59.com/B07Sa4cB1Zd3GeqP33ku - KeithB
@Andy_Vulhop - 这从来没有阻止过任何人,但我同意我们看代码会更有效率。 - Hugh Brackett
你确定这不是作业吗?没有发布代码,再加上你只想要“常见可能性列表”的评论似乎有点奇怪。 - Dan
12个回答

19
以多种方式:
  • 使用涉及数据竞争的多个线程,
  • 将当前系统时间用作输入,
  • 使用未初始化的变量,
  • ...
我们当然可以做出更多的猜测,但如果您想获得有意义的帮助,也许公开代码的相关部分会很好 :-)

是的,我们需要代码!当然,所有这些因素以及十进制误差和伪随机化在运行于确定性机器上时从技术上讲都是确定性的。当我们无法跟踪或理解输入以及程序在不太个人控制的时间共享系统背景下的数百万渐进状态时,它们只是对我们呈现出非确定性。这就是为什么理论和计算机科学始终很重要,需要与实际编程技能一起教授的原因。 - Peter DeWeese
我应该明确表示,我只需要一个常见可能性列表,这也是我得到的。谢谢。 - zoo
顺便提一下,未初始化的变量在没有附加调试器的情况下实际上是确定性的;但是它们以与单线程堆破坏相同的方式是确定性的,这不是您想要的确定性。 - Joshua

8

如果您的输出依赖于在堆上分配的地址:

int main(int argc, char* argv[])
{
   printf("%p", malloc(42));
   return 0;
}

对于每次运行,malloc() 函数可能会返回不同的虚拟地址-更不用说在分配失败时返回NULL了。


3
不错的发现。堆栈地址随机化现在是一个相当标准的功能。如果指针被用作某个地方的键,则会产生影响。我曾在几个场合使用过这个功能,使排序稳定(如果键相等,则比较指针)。 - Dummy00001
虽然,你必须非常不幸或者内存非常低才会出现分配失败。 - zneak
如果堆分配的对象按其地址排序,例如如果指向它们的指针存储在有序容器(如集合)中,则输出将取决于在堆上分配的地址。 - Richard

7

可能是以下情况:

  • 线程定时(Thread timing)
  • 任何类型的输入(用户、文件、网络等)

5
如果您的程序使用浮点/双精度,那么在某些架构上进行上下文切换可能会导致结果差异。
在x86上,FPU对中间结果使用扩展精度,但是当保存到内存中时(发生进程或线程的上下文切换时),这种精度会丢失。这可能会导致结果略微分歧(我们在程序中检测到了这样的问题)。避免此问题的一种方法是要求编译器不使用FPU而使用SSE进行浮点运算。 http://www.network-theory.co.uk/docs/gccintro/gccintro_70.html

4

除了偶然调用rand()函数之外,

rand()函数只要输入相同的初始种子值,就完全是确定性的。


3

如果没有看到一些代码(提示:代码),我能想到的最好的方法就是寻找模式。也许是与日期时间有关的模式。

此外,尝试查找竞态条件。这可能看起来不确定。


2

使用指针的值而不是它所指向的内容总是会产生有趣的结果。


1
在不怎么与“外部世界”交互的程序中,非确定性的流行源是依赖于指针比较。偶尔你可能会在代码中看到它:当一个字典序比较函数没有更多要比较的东西(所有的东西都相等)时,它将对象的地址作为最后的手段进行比较。如果对象在动态内存中分配,这可能会产生不同的排序,因为实际的分配位置可能因平台而异,并且每次运行时都可能会发生变化。

0

显然是月相 bug 的一个新实例。


0
  • 来自网络/互联网的输入。
  • 日期/时间

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接