javascript - Emscripten 中的 "Big"整数

标签 javascript c node.js emscripten

我正在使用 Emscripten 并编译一些简单的程序来测试它的性能。这是我快速组合的一个 fib(n) 算法。实现并不重要,但如果您需要的话,这里是源代码:

#include <stdlib.h>
#include <stdio.h>

#define KEY_TYPE unsigned int
#define VALUE_TYPE unsigned long long

// Simple linked list implementation
typedef struct list{
    KEY_TYPE key;
    VALUE_TYPE value;
    struct list* next;
} list;

void free_list(list** headPtr){
    list* head = *headPtr;
    while(head){
        list* next = head->next;
        free(head);
        head = next;
    }
}

VALUE_TYPE lookup_list(list** headPtr, KEY_TYPE key){
    for(list* head = *headPtr; head; head = head->next){
        if(head->key == key){
            return head->value;
        }
    }
    return 0;
}

void add_list(list** headPtr, list* block){
    block->next = *headPtr;
    *headPtr = block;
}

VALUE_TYPE fib_recur(list** lookup, KEY_TYPE n){
    VALUE_TYPE value;
    // base cases
    if(n < 2)   return n;

    // look for cached answer
    value = lookup_list(lookup, n);
    if(value > 0)   return value;

    // calculate answer
    value = fib_recur(lookup, n - 1) + fib_recur(lookup, n - 2);

    list* head = calloc(sizeof(list), 1);
    head->key = n;
    head->value = value;
    add_list(lookup, head);

    return value;
}


VALUE_TYPE fib(n){
    list* listPtr = NULL;
    VALUE_TYPE num = fib_recur(&listPtr, n);
    free_list(&listPtr);
    return num;
}

int main(int argc, char** argv){
    if(argc != 2)   return 1;

    KEY_TYPE key;
    sscanf(argv[1], "%d", &key); 
    VALUE_TYPE value = fib(key);
    printf("fib(%d) = %lld\n", key, value);
    return 0;
}

C 中的实际实现是正确的(通过使用 clang 编译进行测试。)在 Node.js 中,它对于小整数效果很好,但是当我尝试 47 时,fib(47) 返回 -1323752223不正确。

var Module = require("./fib.js");
var fib = Module.cwrap("fib", "number", ["number"]);

for(var i = 1; i <= 90; i++){
    console.log(i, fib(i));
}
45 1134903170
46 1836311903
47 -1323752223  <-- overflow?
48 512559680    <-- all numbers are incorrect after this point
49 -811192543

这是为什么呢?我用来编译C代码的命令如下:

emcc fib.c -O1 -o fib.js -s EXPORTED_FUNCTIONS="['_fib']"

最佳答案

据我所知,在 JS 中,所有数字都表示为 double,并且使用它们来模拟 Asm.js 子集中的整数。但是64位int不能用double表示,所以据我所知,在Emscripten调用约定中,long long的最高32位是使用一些全局临时变量返回的。

使用调试信息编译程序(-g3 编译器选项)(您可能必须尝试不同的优化级别:在 -O0 上生成的代码可能噪音太大,但在 -O3 上可能不容易理解)并检查您的 main 函数以了解 _fib 的调用方式以及如何调用获取返回值。但我担心,这种调用约定可能会在未来的 Emscripten 版本中发生变化。同时,你可以尝试阅读Emscripten的val.hbind.h的文档,但我自己从未使用过它们。

关于javascript - Emscripten 中的 "Big"整数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47323018/

相关文章:

javascript - 使用 Nodejs 在 Mysql 中插入多个值并通过响应通知用户

javascript - Angularjs: Angular 中的嵌套重复不起作用

c - 删除 ascii float 中的小数点而不截断或精度损失

javascript - 停止在特定链接上执行 javascript

c - GCC ARM C 编译器不遵守 -std=c99 的 %llx printf 格式化代码

c - JPEG类别编码按位运算

android - 如何从socket.io 1.2迁移到socket.io 0.9.16?

node.js - Node 模块 ifx_db 在 linux 中安装失败

javascript - 为什么这个属性没有为函数类定义,而是为相同的实例定义?

javascript - 具有相同类的容器具有单独的 jquery 效果