2012-05-12 3 views
0

Можно создать дубликат:
Is JavaScript's Math broken?Javascript: Прецизионное странное поведение

Предположим,

var x = .6 - .5; 

var y = 10.2 – 10.1; 

var z = .2 - .1; 

результат сравнения

x == y;  // false 

x == .1; // false 

y == .1; // false 

но

z == .1; // true 

Почему Javascript показать такое поведение?

+2

Ваши первые два сравнения немного странны. Почему вы ожидаете, что они совпадут? (-0.1 vs 0.1) – Mat

+0

Связано с: http://stackoverflow.com/questions/1458633/elegant-workaround-for-javascript-floating-point-number-problem – BasTaller

ответ

6

Поскольку плавающая точка не является абсолютно точной. Вы можете получить минус отличия.

(Примечание стороны: Я думаю, что вы имели в виду var x = .6 - .5; В противном случае, вы сравниваете -0.1 с 0.1.)

JavaScript использует IEEE-754 двойной точности 64-бит с плавающей точкой (ref). Это чрезвычайно хорошее приближение чисел с плавающей запятой, но нет идеального способа представления всех чисел с плавающей запятой в двоичном формате.

Некоторые несоответствия легче увидеть, чем другие. Например:

console.log(0.1 + 0.2); // "0.30000000000000004" 

Есть некоторые библиотеки JavaScript там, которые делают «десятичный» вещь a'la С # decimal типа или в Java BigDecimal. Вот где число фактически хранится как серия десятичных цифр. Но они не панацея, у них просто другой класс проблем (попробуйте представить, например, 1/3). «Десятичные» типы/библиотеки являются фантастическими для финансовых приложений, потому что мы привыкли разбираться со стилем округления, требуемым в финансовых материалах, но есть затраты, которые они имеют тенденцию быть медленнее, чем плавающая точка IEEE.

Давайте выход ваши x и y значения:

var x = .6 - .5; 
console.log(x); // "0.09999999999999998" 

var y = 10.2 - 10.1; 
console.log(y); // "0.09999999999999964" 

Нет большой сюрприз, что 0.09999999999999998 является != к 0.09999999999999964.:-)

Вы можете рационализировать те немного, чтобы сделать сравнение работы:

function roundTwoPlaces(num) { 
    return Math.round(num * 100)/100; 
} 

var x = roundTwoPlaces(0.6 - 0.5); 

var y = roundTwoPlaces(10.2 - 10.1); 

console.log(x);  // "0.1" 
console.log(y);  // "0.1" 
console.log(x === y); // "true" 

Или более обобщенное решение:

function round(num, places) { 
    var mult = Math.pow(10, places); 
    return Math.round(num * mult)/mult; 
} 

Live example | source

Обратите внимание, что в полученном числе может быть погрешность точности, но по крайней мере два числа, которые очень, очень, очень близки друг к другу, если они проходят через round с таким же количеством мест, должны заканчиваться (даже если это число не совсем точно).

+0

Никогда не рассчитывайте на точность числа float-кода JavaScript. . =)) – benqus

+0

@benqus: Enh, это достаточно хорошо для большинства целей. И помните, что это не просто JavaScript; многие системы используют IEEE-754, что является причудливым умным битом. –

+0

Этот последний трюк, который вы делаете, есть интересный помощник! Я имею в виду, что это безумие, независимо от того, какой стандарт использует JS. =) Я собираюсь сохранить это решение, если вы не возражаете. Это работает с меньшими номерами, например: 0.00245? – benqus

Смежные вопросы