Ошибка при вычислении значения с плавающей точкой с использованием NodeJS N-API
Здравствуйте все,
Исходя из мира веб-разработки. В настоящее время я пытаюсь сделать некоторый код C, который преобразует значение RGB в значение XYZ, которое может использоваться NodeJS через N-API. Вопрос, который у меня есть, касается расчета с плавающей точкой. Ниже приводится объяснение моей проблемы:
На основе этого кода 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);
Более того, когда я пытаюсь вызвать код JS через travis, который также работает под управлением OSX, а в Ubuntu через Docker, код JS также выводит правильное значение.
Может ли это быть в большей степени связано с аппаратным обеспечением или с тем, как я собираю свои библиотеки, или с чем-то еще?
Заранее спасибо.
2 ответа
В самом деле, как Jack Pointy и Jack, JavaScript-номера являются 64- Jack.
Когда я кодировал эту функцию, использовался числовой тип float (на первый взгляд я не думал о создании модуля Node). Позже я решил сделать преобразование из float в double, используя небольшой метод util, как показано ниже.
double v = *(double *) arg;
status = napi_create_double(env, v, &value);
Странно кажется, что я мог бы случайно потерять десятичную точность при выполнении этого преобразования, в то время как это не должно было иметь (32 бита на 64 бита), или я мог что-то упустить.
Позже я произвожу рефакторинг того же кода, но на этот раз, используя вместо этого double, и он будет работать как надо. Большое спасибо всем вам.
Примечание: так как я использовал этот метод кода кода выше через базу кодов привязки NodeJS, я удивлен, что у меня не было ошибки десятичной точности ранее.
В движке javascript v8. На самом деле существуют только smi и double. readFloatBE: когда float перейдет к v8, float будет приведен к удвоению. это будет способствовать удвоению, когда вы выйдете и округлите в поплавок.
Во-первых, если вы действительно хотите получить значение наподобие C, вам нужно вручную указать округленные цифры и повторно создать экземпляр объекта Number с функцией Number.prototype.toPrecision, округленной в большую сторону:
Для справки:
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)))