Ошибка при вычислении значения с плавающей точкой с использованием 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)))
Другие вопросы по тегам