1

大家好,

来自网络开发世界。我目前正在尝试做一些 C 代码,它将 RGB 值转换为 NodeJS 可以通过 N-API 使用的 XYZ 值。我遇到的问题是关于浮动计算。以下是我的问题的解释:

根据下面的 C 代码,此代码尝试将 RGB 值转换为 XYZ 值。

char * colorType = getStringValue(env, funcParams[2], SPACELen);
// m is either the value srgb | adobeRgb
Matrix m = getEnumFromStr(colorType);
Rgb * rgb = getRGBFromJSObj(env, funcParams[0]);
xyz = generateXyzFromRgb(rgb, m);

我正在使用这个 JS 片段来调用我的库

const rgb = {
  r: 255,
  g: 255,
  b: 255
};

const xyz = lib.getXyzFromRgb(rgb, "srgb", 10000);
expect(xyz).to.be.deep.equal({
  x: 0.9504,
  y: 1,
  z: 1.0888
});

如果一切正常,输出应该如下所示

{
 x: 0.9504,
 y: 1,
 z: 1.0888 
}

但是我的输出是这个

{
 x: 0.9502,
 y: 0.9997,
 z: 1.0886 
}

如您所见,输出完全错误。然而,这个错误的输出只发生在我的本地机器(OSX)上,并且只有当我尝试使用 JS 片段进行转换时。

实际上,当我尝试直接通过 Xcode 使用下面的这段代码运行转换时,输出是正确的

// RGB and & m variable is outputing the same value as the conversion done by the C code above
xyz = generateXyzFromRgb(rgb, m);

此外,当我尝试通过运行 OSX 的 travis 调用 JS 代码时,以及通过 Docker 在 Ubuntu 上调用 JS 代码时,JS 代码也会输出正确的值

它是否与硬件或我编译库的方式更相关?

先感谢您。

4

2 回答 2

2

在 javascript v8 引擎中。实际上只存在smi和double。readFloatBE:当 float 传递到 v8 时,float 将被强制转换为 double。当你出去并四舍五入变成浮动时,它将提升为双倍。

首先,如果你真的想得到像 C 一样的值,你需要手动指定四舍五入的数字,并用 Number.prototype.toPrecision 函数四舍五入重新实例化 Number 对象:

供你参考:

var v = 5.2
var buffer = new Buffer(5)
buffer.writeFloatBE(v)
var g = buffer.readFloatBE()

console.log(v)
console.log(g)
console.log(v==g)
console.log(Number(g.toPrecision(5)))
于 2018-11-21T00:49:20.340 回答
0

事实上,正如Pointyuser10683038所发布的, JavaScript 数字是 64 位的。

当我编写此功能时,使用的数字类型是浮点数(乍一看并没有考虑制作 Node 模块)。后来我决定使用下面的小工具方法从浮点数转换为双精度数

double v = *(double *) arg;
status = napi_create_double(env, v, &value);

奇怪的是,在进行此转换时,我可能会随机丢失小数精度,而它不应该(32 位到 64 位),或者我可能遗漏了一些东西。

后来我重构了相同的代码,但这次使用 double代替,它可以正常工作。非常感谢你们所有人。

注意:当我在 NodeJS 绑定代码库中使用上面的这个 util 代码时,我很惊讶我之前没有遇到小数精度错误。

于 2018-11-21T21:35:22.293 回答