使用 NativeCall 调用 C fn `erf` 比 C 中的 `erf` 获得更精确的输出
Using NativeCall to call the C fn `erf` gets more precise output than `erf` in C
我写了一个 Raku 脚本来调用 C 标准库中的 erf
函数:
use NativeCall;
sub erf(num64) returns num64 is native { * };
say [0.5,1,2,3,4,-0.9].map: {erf($_.Num)};
这个脚本的输出
(0.5204998778130465 0.8427007929497149 0.9953222650189527 0.9999779095030014 0.9999999845827421 -0.7969082124228322)
与 C 的所有值 [0.5,1,2,3,4,-0.9]
的输出匹配,除了 4
.
对于 4
C 输出 1.000000
而 Raku 给出 0.9999999845827421
.
要在 C 中测试 4
的输出,运行 此代码:
#include <stdio.h> // Including header file for printf function
#include <math.h> // Including header file for erf function
int main (){
double param, result;
param = 4.0;
result = erf(param);
printf("erf (%f) = %f\n", param, result);
return 0;
}
知道发生了什么事吗?我也需要从 Raku 输出 1.0
。
对于 C 代码,将 %f
更改为 %.99g
以显示更多数字。这揭示了 erf(4)
returns 0.9999999845827420852373279558378271758556365966796875.
%f
要求小数点后六位。该值四舍五入以适合该格式。 %.<i>number</i>f
请求小数点后 <i>number</i>
位数点并始终使用“固定”格式。 %.<i>number</i>g
请求 <i>number</i>
有效数字并使用一个“通用”格式,在适当的时候切换到指数表示法。
对于Raku代码,如果你想输出“1.0”或“1.000000”,你需要对输出应用一些格式化请求。我不练习 Raku,但简短的搜索显示 Raku 具有可以使用的 printf
-like 功能,因此请求 %f
格式应该复制 C 输出。
你是在比较苹果和橙子。
use NativeCall;
sub erf(num64) returns num64 is native { * };
say .fmt("%f") for [0.5,1,2,3,4,-0.9].map: {erf($_.Num)}
0.520500
0.842701
0.995322
0.999978
1.000000
-0.796908
你在 C 中使用 printf
,如果你使用 .fmt
(在 Raku 中更容易说 sprintf
),那么你也会得到 1.0
.
另一个基于@Eric 关于精度的解释的版本:
my $fmt = '%.6f';
printf [$fmt ~ ' '] x 5 ~ $fmt ~ "\n", [0.5,1,2,3,4,-0.9].map: {erf($_.Num)};
[$fmt ~ ' '] x 5 ~ $fmt ~ "\n"
构建格式字符串 "%.6f %.6f %.6f %.6f %.6f %.6f\n"
输出
0.520500 0.842701 0.995322 0.999978 1.000000 -0.796908
甚至更多raku as proposed by raiph, using the infix operator xx
:
printf "{'%.6f' xx 6} \n", [0.5,1,2,3,4,-0.9].map: {erf($_.Num)};
我写了一个 Raku 脚本来调用 C 标准库中的 erf
函数:
use NativeCall;
sub erf(num64) returns num64 is native { * };
say [0.5,1,2,3,4,-0.9].map: {erf($_.Num)};
这个脚本的输出
(0.5204998778130465 0.8427007929497149 0.9953222650189527 0.9999779095030014 0.9999999845827421 -0.7969082124228322)
与 C 的所有值 [0.5,1,2,3,4,-0.9]
的输出匹配,除了 4
.
对于 4
C 输出 1.000000
而 Raku 给出 0.9999999845827421
.
要在 C 中测试 4
的输出,运行 此代码:
#include <stdio.h> // Including header file for printf function
#include <math.h> // Including header file for erf function
int main (){
double param, result;
param = 4.0;
result = erf(param);
printf("erf (%f) = %f\n", param, result);
return 0;
}
知道发生了什么事吗?我也需要从 Raku 输出 1.0
。
对于 C 代码,将 %f
更改为 %.99g
以显示更多数字。这揭示了 erf(4)
returns 0.9999999845827420852373279558378271758556365966796875.
%f
要求小数点后六位。该值四舍五入以适合该格式。 %.<i>number</i>f
请求小数点后 <i>number</i>
位数点并始终使用“固定”格式。 %.<i>number</i>g
请求 <i>number</i>
有效数字并使用一个“通用”格式,在适当的时候切换到指数表示法。
对于Raku代码,如果你想输出“1.0”或“1.000000”,你需要对输出应用一些格式化请求。我不练习 Raku,但简短的搜索显示 Raku 具有可以使用的 printf
-like 功能,因此请求 %f
格式应该复制 C 输出。
你是在比较苹果和橙子。
use NativeCall;
sub erf(num64) returns num64 is native { * };
say .fmt("%f") for [0.5,1,2,3,4,-0.9].map: {erf($_.Num)}
0.520500
0.842701
0.995322
0.999978
1.000000
-0.796908
你在 C 中使用 printf
,如果你使用 .fmt
(在 Raku 中更容易说 sprintf
),那么你也会得到 1.0
.
另一个基于@Eric 关于精度的解释的版本:
my $fmt = '%.6f';
printf [$fmt ~ ' '] x 5 ~ $fmt ~ "\n", [0.5,1,2,3,4,-0.9].map: {erf($_.Num)};
[$fmt ~ ' '] x 5 ~ $fmt ~ "\n"
构建格式字符串 "%.6f %.6f %.6f %.6f %.6f %.6f\n"
输出
0.520500 0.842701 0.995322 0.999978 1.000000 -0.796908
甚至更多raku as proposed by raiph, using the infix operator xx
:
printf "{'%.6f' xx 6} \n", [0.5,1,2,3,4,-0.9].map: {erf($_.Num)};