Emscripten 中的“大”整数
Posted
技术标签:
【中文标题】Emscripten 中的“大”整数【英文标题】:"Big" integers in Emscripten 【发布时间】:2017-11-16 06:27:05 【问题描述】:我正在使用 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']"
【问题讨论】:
emscripten-1.37.1 和 emscripten-1.35.0 看起来没有溢出。 【参考方案1】:在 JS 中的 AFAIK,您将所有数字表示为 double
s,并且使用它们模拟 Asm.js 子集中的整数。但是 64 位 int 不能用 double
表示,所以据我记得,在 Emscripten 调用约定中,long long
的最高 32 位是使用一些全局临时变量返回的。
使用调试信息编译您的程序(-g3
编译器选项)(您可能必须尝试不同的优化级别:在-O0
上生成的代码可能太吵了,但在-O3
上可能不容易了解)并检查您的 main
函数,了解您的 _fib
是如何被调用的以及返回值是如何获取的。但我担心,这种调用约定可能会在未来的 Emscripten 版本中发生变化。同时,您可以尝试阅读 Emscripten 的 val.h
和 bind.h
上的文档,但我自己从未使用过。
【讨论】:
以上是关于Emscripten 中的“大”整数的主要内容,如果未能解决你的问题,请参考以下文章
使用 Clang 编译的可执行文件中的 emscripten
您如何在 emscripten 中迭代 Box2D 中的实体列表?
如何使用 Emscripten 编译的程序中的 wasm-bindgen?