GNU MP 使用 mpf_pow 函数时精度低
GNU MP low precision while using mpf_pow function
在编写 WolframAlpha 给出的 , I used the mpf_pow
function to calculate 12.3 ^ 123
, and the result is different from the one 时(顺便说一句,它也使用 GMP)。
我将代码转换为纯 C 以简化:
#include <stdio.h>
#include <gmp.h>
int main (void) {
mpf_t a, c;
unsigned long int b = 123UL;
mpf_set_default_prec(100000);
mpf_inits(a, c, NULL);
mpf_set_d(a, 12.3);
mpf_pow_ui(c, a, b);
gmp_printf("c = %.50Ff\n", c);
return 0;
}
结果是
114374367934618002778643226182707594198913258409535335775583252201365538178632825702225459029661601216944929436371688246107986574246790.32099077871758646985223686110515186972735931183764
虽然 WolframAlpha returns
1.14374367934617190099880295228066276746218078451850229775887975052369504785666896446606568365201542169649974727730628842345343196581134895919942820874449837212099476648958359023796078549041949007807220625356526926729664064846685758382803707100766740220839267 × 10^134
在第 15 位开始与 mpf_pow
不一致。
我是不是在代码中做错了什么,这是 GMP 的限制,还是 WolframAlpha 给出了错误的结果?
这给出了类似于 WolframAlpha 的结果:
from decimal import Decimal
from decimal import getcontext
getcontext().prec = 200
print(Decimal('12.3') ** 123)
所以你的 GMP 配置一定有问题。
Am I doing something wrong in the code, is this a limitation of GMP, or is WolframAlpha giving an incorrect result?
您正在做的事情与 Wolfram 正在做的事情不同(很明显)。您的代码没有错,本身,但它并没有按照您可能认为的那样做。比较此变体的输出:
#include <stdio.h>
#include <gmp.h>
int main (void) {
mpf_t a, c;
unsigned long int b = 123UL;
mpf_set_default_prec(100000);
mpf_inits(a, c, NULL);
mpf_set_d(a, 12.3);
mpf_pow_ui(c, a, b);
gmp_printf("c = %.50Ff\n", c);
putchar('\n');
mpf_t a1, c1;
mpf_inits(a1, c1, NULL);
mpf_set_str(a1, "12.3", 10);
mpf_pow_ui(c1, a1, b);
gmp_printf("c' = %.50Ff\n", c1);
return 0;
}
...
c = 114374367934618002778643226182707594198913258409535335775583252201365538178632825702225459029661601216944929436371688246107986574246790.32099077871758646985223686110515186972735931183764
c' = 114374367934617190099880295228066276746218078451850229775887975052369504785666896446606568365201542169649974727730628842345343196581134.89591994282087444983721209947664895835902379607855
两个输出值之间的差异是因为我的 C 实现和你的实现以二进制浮点数表示 double
类型的值,而 12.3 在二进制浮点数中不能完全表示(参见 Is floating point math broken?)。 C 提供了最接近的可用近似值,假设使用 64 位 IEEE 754 表示,它与大约 15 位十进制数字的精度相匹配。当您使用这样的值初始化 GMP 变量时,您将获得实际 double
值的精确 GMP 表示,这只是十进制 12.3 的近似值。
但是 GMP 可以将 12.3(十进制)表示为您选择的任何精度。*您选择了非常高的精度,因此当您使用十进制字符串初始化 MP-float 时与使用 double
相比,您可以获得更接近的近似值。当然,对这些不同的值执行相同的操作会产生不同的结果。后一种情况下的 GMP 结果似乎与 Wolfram 结果一致,完全精确地表达了它。
另请注意,在一般意义上,也可以在软件或硬件(如果您具备这种能力)中使用十进制浮点数。值 12.3(十进制)可以用这种格式准确表示,但这不是 GMP 使用的格式。
* 或者实际上,GMP 可以将 12.3 准确地 表示为 MP 有理数,尽管上面的代码不是这样做的。
在编写 WolframAlpha 给出的 mpf_pow
function to calculate 12.3 ^ 123
, and the result is different from the one 时(顺便说一句,它也使用 GMP)。
我将代码转换为纯 C 以简化:
#include <stdio.h>
#include <gmp.h>
int main (void) {
mpf_t a, c;
unsigned long int b = 123UL;
mpf_set_default_prec(100000);
mpf_inits(a, c, NULL);
mpf_set_d(a, 12.3);
mpf_pow_ui(c, a, b);
gmp_printf("c = %.50Ff\n", c);
return 0;
}
结果是
114374367934618002778643226182707594198913258409535335775583252201365538178632825702225459029661601216944929436371688246107986574246790.32099077871758646985223686110515186972735931183764
虽然 WolframAlpha returns
1.14374367934617190099880295228066276746218078451850229775887975052369504785666896446606568365201542169649974727730628842345343196581134895919942820874449837212099476648958359023796078549041949007807220625356526926729664064846685758382803707100766740220839267 × 10^134
在第 15 位开始与 mpf_pow
不一致。
我是不是在代码中做错了什么,这是 GMP 的限制,还是 WolframAlpha 给出了错误的结果?
这给出了类似于 WolframAlpha 的结果:
from decimal import Decimal
from decimal import getcontext
getcontext().prec = 200
print(Decimal('12.3') ** 123)
所以你的 GMP 配置一定有问题。
Am I doing something wrong in the code, is this a limitation of GMP, or is WolframAlpha giving an incorrect result?
您正在做的事情与 Wolfram 正在做的事情不同(很明显)。您的代码没有错,本身,但它并没有按照您可能认为的那样做。比较此变体的输出:
#include <stdio.h>
#include <gmp.h>
int main (void) {
mpf_t a, c;
unsigned long int b = 123UL;
mpf_set_default_prec(100000);
mpf_inits(a, c, NULL);
mpf_set_d(a, 12.3);
mpf_pow_ui(c, a, b);
gmp_printf("c = %.50Ff\n", c);
putchar('\n');
mpf_t a1, c1;
mpf_inits(a1, c1, NULL);
mpf_set_str(a1, "12.3", 10);
mpf_pow_ui(c1, a1, b);
gmp_printf("c' = %.50Ff\n", c1);
return 0;
}
...
c = 114374367934618002778643226182707594198913258409535335775583252201365538178632825702225459029661601216944929436371688246107986574246790.32099077871758646985223686110515186972735931183764
c' = 114374367934617190099880295228066276746218078451850229775887975052369504785666896446606568365201542169649974727730628842345343196581134.89591994282087444983721209947664895835902379607855
两个输出值之间的差异是因为我的 C 实现和你的实现以二进制浮点数表示 double
类型的值,而 12.3 在二进制浮点数中不能完全表示(参见 Is floating point math broken?)。 C 提供了最接近的可用近似值,假设使用 64 位 IEEE 754 表示,它与大约 15 位十进制数字的精度相匹配。当您使用这样的值初始化 GMP 变量时,您将获得实际 double
值的精确 GMP 表示,这只是十进制 12.3 的近似值。
但是 GMP 可以将 12.3(十进制)表示为您选择的任何精度。*您选择了非常高的精度,因此当您使用十进制字符串初始化 MP-float 时与使用 double
相比,您可以获得更接近的近似值。当然,对这些不同的值执行相同的操作会产生不同的结果。后一种情况下的 GMP 结果似乎与 Wolfram 结果一致,完全精确地表达了它。
另请注意,在一般意义上,也可以在软件或硬件(如果您具备这种能力)中使用十进制浮点数。值 12.3(十进制)可以用这种格式准确表示,但这不是 GMP 使用的格式。
* 或者实际上,GMP 可以将 12.3 准确地 表示为 MP 有理数,尽管上面的代码不是这样做的。