如何在 Elixir NIF 中处理大整数

问题描述 投票:0回答:1

我用 C 语言编写了一个快速排序的实现作为 Elixir NIF。我知道有一个 BIF,我这样做只是为了自学 NIF。

现在我的代码到目前为止可以工作,也就是说,我可以调用

MyQuicksort.my_quicksort([1,100,2])
并按预期返回
[1,2,100]
。然而,elixir 整数可以是任意大,如果我调用
MyQuicksort.my_quicksort([123, 67_845_734_623_721_230_492_834, 1])
,我会得到
~c"get_int gone wrong"
。这是我自己的错误消息,但要点是
enif_get_long
对于大整数值不会成功。在 https://www.erlang.org/doc/man/erl_nif 上,所有用于整数类型的
enif_get_$TYPE
函数都有一些提示,例如“如果
term
超出类型范围,则返回 false”。

因此,我的问题是是否有办法在 NIF 函数内处理此类整数。 这是我用来将 Elixir 列表转换为 C 数组的代码。

static ERL_NIF_TERM my_quicksort(ErlNifEnv *env, int argc,
                                 const ERL_NIF_TERM argv[]) {
  uint size;
  if (!enif_get_list_length(env, argv[0], &size))
    return enif_make_string(env, "get_list_cell gone wrong", ERL_NIF_UTF8);
  if (size > INT_MAX)
    return enif_make_string(env, "list size too large", ERL_NIF_UTF8);
  long n[size];
  ERL_NIF_TERM head;
  ERL_NIF_TERM old_tail = argv[0];

  ERL_NIF_TERM new_tail;

  for (int i = 0; i < size; i++) {
    if (!enif_get_list_cell(env, old_tail, &head, &new_tail))
      return enif_make_string(env, "get_list_cell gone wrong", ERL_NIF_UTF8);
    if (!enif_get_long(env, head, &n[i]))
      return enif_make_string(env, "get_int gone wrong", ERL_NIF_UTF8);

    old_tail = new_tail;
  }

  quicksort(n, 0, size - 1);

我知道为什么我的程序会像我所描述的那样运行。我觉得我只是缺少正确的

enif_get_$TYPE
函数来解构此类整数。

c elixir biginteger ffi erlang-nif
1个回答
0
投票

好吧,所以,我自己回答这个问题,到目前为止我发现的是比较两个

enif_compare
ERL_NIF_TERM
函数。

这意味着我只需将表示列表的

ERL_NIF_TERM
转换为包含其所有元素的数组即可排序。这是我在答案中列出的代码部分在我融入这个想法后的样子。

static ERL_NIF_TERM my_quicksort(ErlNifEnv *env, int argc,
                                 const ERL_NIF_TERM argv[]) {
  uint size;

  if (!enif_get_list_length(env, argv[0], &size))
    return enif_make_string(env, "get_list_cell gone wrong", ERL_NIF_UTF8);
  if (size > INT_MAX)
    return enif_make_string(env, "list size too large", ERL_NIF_UTF8);

  ERL_NIF_TERM n[size];
  ERL_NIF_TERM head;
  ERL_NIF_TERM old_tail = argv[0];
  ERL_NIF_TERM new_tail;

  for (uint i = 0; i < size; i++) {
    if (!enif_get_list_cell(env, old_tail, &n[i], &new_tail))
      return enif_make_string(env, "get_list_cell gone wrong", ERL_NIF_UTF8);

    old_tail = new_tail;
  }

  quicksort(n, 0, size - 1);

  return enif_make_list_from_array(env, n, size);

然后只需相应调整

quicksort
函数中使用的类型以及它使用的排序函数即可。

请注意,如果您忘记实际使用

enif_compare(x,y) > 0
来代替
x > y
,您不会收到错误,但仍然无法获得大数字所需的行为。

完成此操作后,我可以拨打电话

MyQuicksort.my_quicksort([
    123,
    97_845_734_623_721_230_492_834,
    67_845_734_623_721_830_492_834,
    111,
    67_845_734_623_721_230_492_111,
    9909
  ])

并实际取回排序后的列表。

© www.soinside.com 2019 - 2024. All rights reserved.