我想写的是numpylinspace函数.

由于循环在编译代码中速度更快,我try 在c中编写并从Raku调用.

//  C code
#include <stdio.h> 
#ifdef _WIN32 
#define DLLEXPORT __declspec(dllexport)
#else 
#define DLLEXPORT extern // if c++ code, requires extern "C"
#endif

DLLEXPORT void c_linspace(double start, double step, int num, double* vals) {
    for (int i = 0; i < num; i++)
{
    vals[i] = start;
    start += step;
}
}
// Raku code
sub c_linspace(num64, num64, int32, CArray[num64]) 
    is native( MYDYN) { * };

sub raku_linspace($start, $end, $num, :$endpoint = True, :$retstep = False) {
    my $step = $endpoint ?? ($end - $start)/($num - 1) !!  ($end-$start)/($num);
    my $vals = CArray[num64].allocate($num);
    c_linspace($start.Num, $step.Num, $num.Int, $vals);
    $retstep ?? ($vals.list, $step) !! $vals.list
}

工作正常.但判断结果的精确度,例如:

Raku给

say raku_linspace(1,3,300000)[200]   # gives 1.0013333377777869

numpy给了

import numpy as np
arr = np.linspace(1,3,300000)[200]
print(arr) # gives 1.0013333377777927

为什么在精确度上会有这样的差异?我的期望是double应该保持15位小数的精确度.

文档https://docs.raku.org/language/nativetypes提到的double被映射到num64.

还提到了Rakudo特定的类型https://docs.raku.org/language/nativetypes,其中提到了longlonglong.那么long double在乐库映射到了什么地方呢?它似乎不是num64.

System information: Windows 10 64位 GCC 13.2.0


Edit:

看起来问题直接出现在c中,原因是浮点错误,而不是通过本机调用.因为运行C得到了Raku所提供的东西.

然而,在本地是否有机制来处理long doublelong long,最好是举个例子?

也是what could be done,以使此函数具有与numpy相同的精度.任何指向我可以阅读和try 的文档的指针.

推荐答案

我不知道我们是应该取消这个问题的标签,还是编辑它,或者其他事情,但无论如何:这不是一个NativeCall问题,也不是一个Raku问题,这是一个C问题,而这里的"真正"问题是:

为什么我的c_linspacenumpy.linspace产生了不同的结果?

这个问题的答案是:numpy‘S linspace使用了不同的计算,可能是使用了SMP指令.确实如此(稍微简化了一点):

    y = _nx.arange(0, num, dtype=dt).reshape((-1,) + (1,) * ndim(delta))
    step = delta / div
    y *= step
    y += start

C语言的类似功能是:

void c_linspace(double start, double step, int num, double* vals) {
  for (int i = 0; i < num; i++)
    vals[i] = (double) i;
  for (int i = 0; i < num; i++)
    vals[i] *= step;
  for (int i = 0; i < num; i++)
    vals[i] += start;
}

如果您使用此实现,您的Raku代码将返回与numpy版本相同的结果1.0013333377777927.

但是,正如 comments 中所说,即使是

void c_linspace(double start, double step, int num, double* vals) {
  for (int i = 0; i < num; i++)
    vals[i] = i * step + start;
}

就足够了...

回答你的另一个问题,即,

然而,在本地是否有机制来处理long doublelong long,最好是举个例子?

在rakudo中支持long long,该类型在其无符号变体中称为longlongulonglong.long double类型目前还不受支持,但在https://github.com/rakudo/rakudo/blob/main/lib/NativeCall.rakumod中添加对它的支持应该很容易(尽管不是很简单)(重要的部分是完成测试等).

C++相关问答推荐

为指针 struct 创建宏

当包含头文件时,gcc会发出隐式函数声明警告

如何在不修改字符串缓冲区早期使用的情况下覆盖字符串缓冲区

Zig将std.os.argv转换为C类型argv

常数函数指针优化

字符串令牌化xpath表达式

数据包未从DPDK端口传输到内核端口

在c++中使用堆栈的有效括号

C++中矢量类型定义和数据保护的高效解决方案

Clang警告称,`ffi_type`与`sizeof`不兼容

C指针概念分段故障

是否需要包括<;errno.h>;才能使用perror?

如何在提取的索引中分配空值?

C:在编译时构建和使用字符串文字的预处理器宏?

如何在不使用字符串的情况下在c中编写函数atof().h>;

如何修复我的qsort()算法?它每次都给出不同的结果

GETS()在C++中重复它前面的行

如何打印循环调度问题的时间表

不兼容的整数到指针转换传递';char';到类型';常量字符*

I';我试着从.txt文件中读取文本,并用c计算其中的单词数量