fal*_*lse 7 c biginteger gmp swi-prolog yap
(我只是主要通过swi-prolog和yap的GMP库的间接用户.但我对解决这个问题非常感兴趣.)
当使用可笑的大值执行取幂时,主机系统或GMP不再能够适当地处理溢出.我已经与上述系统的开发人员进行了交谈,但他们没有看到一个简单的解决方案.
这个问题是否为其他GMP系统/用户所知?你如何处理这种溢出?
作为一个完整性检查首先测试7 ^ 7 ^ 7的值应该是:375982 ... 32343
例如,在32位系统上,查询会?- X is 13^1150000000.产生这样的溢出.以下是YAP给出的内容:
GNU gdb (GDB) 7.0-ubuntu
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu".
For bug reporting instructions, please see:
...
Reading symbols from /opt/gupu/src/yap-6.3/narch-gupu2/yap...done.
(gdb) run -f
Starting program: /opt/gupu/src/yap-6.3/narch-gupu2/yap -f
YAP 6.3.2 (i686-linux): Sun Nov 11 04:19:37 CET 2012
?- X is 13^1150000000.
Program received signal SIGSEGV, Segmentation fault.
0x001638d8 in ?? () from /usr/lib/libgmp.so.3
(gdb) bt
#0 0x001638d8 in ?? () from /usr/lib/libgmp.so.3
#1 0x00164470 in __gmpn_mul_fft () from /usr/lib/libgmp.so.3
#2 0x001646c2 in __gmpn_mul_fft_full () from /usr/lib/libgmp.so.3
#3 0x00165f28 in __gmpn_sqr_n () from /usr/lib/libgmp.so.3
#4 0x0014b58b in __gmpz_n_pow_ui () from /usr/lib/libgmp.so.3
#5 0x0014c4a1 in __gmpz_pow_ui () from /usr/lib/libgmp.so.3
#6 0x080c4a1d in Yap_gmp_exp_int_int (i1=13, i2=1150000000) at ../C/gmp_support.c:939
#7 0x0815f9df in p_exp (t1=, t2=3082051592) at ../C/arith2.c:609
#8 0x080b1f19 in Eval (t=0) at ../C/eval.c:147
#9 0x080b2251 in p_is () at ../C/eval.c:186
#10 0x0806b56a in Yap_absmi (inp=0) at ../C/absmi.c:6912
#11 0x080b3655 in exec_absmi (top=) at ../C/exec.c:1002
#12 0x080b3b1f in do_goal (t=, CodeAdr=, arity=,
pt=0x0, top=1) at ../C/exec.c:1068
#13 0x080b3d1d in Yap_RunTopGoal (t=135918154) at ../C/exec.c:1291
#14 0x08061a6f in YAP_RunGoalOnce (t=135918154) at ../C/c_interface.c:2511
#15 0x0805c2f5 in do_top_goal (argc=2, argv=0xbffff4c4) at ../console/yap.c:84
#16 exec_top_level (argc=2, argv=0xbffff4c4) at ../console/yap.c:131
#17 main (argc=2, argv=0xbffff4c4) at ../console/yap.c:172
(gdb)
编辑:对于64位系统也是如此; 像这样:
Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 6.3.5)
Copyright (c) 1990-2012 University of Amsterdam, VU Amsterdam
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to redistribute it under certain conditions.
Please visit http://www.swi-prolog.org for details.
For help, use ?- help(Topic). or ?- apropos(Word).
?- X is 3445^2^62.
gmp: overflow in mpz type
Abort
Run Code Online (Sandbox Code Playgroud)
然而,
?- X is 2^2^63.
ERROR: Out of global stack
?- X is 2^2^62.
gmp: overflow in mpz type
Abort
Run Code Online (Sandbox Code Playgroud)
从下面:
?- X is 2^2^36.
ERROR: Out of global stack
?- X is 2^2^37.
gmp: overflow in mpz type
Abort
Run Code Online (Sandbox Code Playgroud)
因此,如果数字足够大,则SWI检测到错误 - 因此可以由SWI处理(错误:消息由SWI处理).
不是真正的答案,而是解释 SWI-Prolog 的作用。首先,它估计是否可能发生溢出。如果确定,它将在调用 GMP 之前引发错误。否则,它依赖于 GMP 分配挂钩并在失败时执行 longjmp()。它跟踪为什么分配了哪些内存,并释放为中止的 GMP 操作分配的内存。它可以这样做,因为内存永远不会受到 GMP 的控制。成功的 GMP 计算结果被复制到 Prolog 堆栈并受 Prolog 内存管理的约束。
这曾经有效,但在最近的版本中不起作用。我怀疑 GMP 会估计大小,如果它知道这会失败,它甚至不会调用 malloc() 钩子。我所需要的只是确保始终调用钩子的方法,即使值大得离谱。任何大于 size_t 可以表示的东西都可以用 (size_t)-1 调用钩子。
Ps 由于复制到(较小的)Prolog 运行时堆栈,它比内存可以存储的时间要早得多。