从Raku和C函数返回的数组在nativecall中不匹配

8oomwypt  于 9个月前  发布在  其他
关注(0)|答案(1)|浏览(96)

我想从Raku调用一个C函数https://github.com/wch/r-source/blob/trunk/src/nmath/rmultinom.c#L47。为此,我将Raku函数定义为

use NativeCall;
constant RMATH = "./Rmath.dll";
multi set_seed(uint32, uint32)
    is native( RMATH ) { * };
multi set_seed(UInt() $a, UInt() $b) is export {
    set_seed(my uint32 $ = $a, my uint32 $ = $b)
}
sub rmultinom(int32, CArray[num64], int32, CArray[int32])
    is native( RMATH ) { * }; 

sub raku_rmultinom($n , $size, @prob is copy) is export {
    @prob = @prob.map: {$_.Num};
    my $prob = CArray[num64].new(@prob);
    my $ints = CArray[int32].allocate($size);
    rmultinom($n, $prob, $size, $ints);
    return $ints.list
}

字符串
电话

my @prob = [0.1, 0.3, 0.5, 0.1];
set_seed(123,456);
say raku_rmultinom(100, 5, @prob);


(9 29 49 13 0)

  • 符合 * C代码:
#define MATHLIB_STANDALONE 1
#include "Rmath.h"
#include <stdio.h>

int main(int argc, char** argv) {
    int draws = 100;
    int classes = 5;
    int vals[classes];
    double probs[4] = {0.1, 0.3, 0.5, 0.1};

    set_seed(123, 456);
    rmultinom(draws, probs, classes, vals);

    for(int j=0; j < classes; j++) {
        printf("Count of class %i drawn: %i\n", j, vals[j]);
    }
    return 0;
}
Count of class 0 drawn: 9
Count of class 1 drawn: 29
Count of class 2 drawn: 49
Count of class 3 drawn: 13
Count of class 4 drawn: 0

但是当我将大小增加到10时,请参见下面的示例,输出似乎很奇怪:

my @prob = [0.1, 0.3, 0.5, 0.1];
set_seed(123,456);
say raku_rmultinom(100, 10, @prob);
(0 0 0 0 0 -1 0 0 0 0) # expectation was (9 29 49 13 0 0 0 0 0 0)

的字符串
在C中:

int main(int argc, char** argv) {
    int draws = 100;
    int classes = 10;
    int vals[classes];
    double probs[4] = {0.1, 0.3, 0.5, 0.1};

    set_seed(123, 456);
    rmultinom(draws, probs, classes, vals);

    for(int j=0; j < classes; j++) {
        printf("Count of class %i drawn: %i\n", j, vals[j]);
    }
    return 0;
}
Count of class 0 drawn: 9
Count of class 1 drawn: 29
Count of class 2 drawn: 49
Count of class 3 drawn: 13
Count of class 4 drawn: 0
Count of class 5 drawn: 0
Count of class 6 drawn: 0
Count of class 7 drawn: 0
Count of class 8 drawn: 0
Count of class 9 drawn: 0

在我的Raku代码中实现raku_rmultinom有问题吗?

**系统信息:**这是在Windows 10 64位中完成的。为了重现性,我在这里提供了头部和动态库:https://replit.com/@sumankhanal/rakunativecall

要在同一个文件夹中测试带有Rmath. h头和库的C文件,请移动到该目录并从cmd行运行:

gcc -I. -L. <cfile> -lRmath
.\a.exe

否则,我是这个软件包https://github.com/sumanstats/Statistics的作者,该软件包在全球范围内提供raku_rmultinom,任何人都可以安装和测试输出及其行为。

使用的Raku版本是从https://rakudo.org/dl/rakudo/rakudo-moar-2023.09-01-win-x86_64-msvc.zip;raku -v下载的,提供:

Welcome to Rakudo™ v2023.09.
Implementing the Raku® Programming Language v6.d.
Built on MoarVM version 2023.09.

zyfwsgd6

zyfwsgd61#

我认为这是值得总结的事情发生在这样。
首先,@Suman(提问者)的结论(在他们问题下面的评论中)是答案“看起来像”什么:

@prob.append(0 xx $size - @prob)

字符串
这反映了这样一个事实,即对于这个Q,有时在桥接C和Raku之间的差距时就是这种情况,问题在于,(在Raku中编码时通常是有意义的)和C规范(通常在C中编码时有意义)而不是任何一方的技术问题。评论交流中的一些摘录说明了深入了解这一问题的过程。不匹配:
在Ubuntu上测试.输出如预期:(9 29 49 13 0 0 0 0 0 0)
Raku是一种动态语言,C是静态的。你需要非常小心数组的大小。4没有问题,因为它正好是@prob数组的大小。
在Raku部分,当$size > +@prob时,您正在调用未定义的行为.
在C中,当你声明一个变量但没有初始化它时,它将被赋予一个“垃圾”值,即,任何碰巧位于指定给变量的内存地址的值。对于数组,它的所有元素都将具有谁知道的值,如1635326112327580。另一方面,在Rakudo的NativeCall中,.allocate方法恰好用0 s显式地初始化数组元素,所以你有所有的0 s(除了那个-1)。

相关问题