2010-03-19 3 views
3

Существует некоторая проблема, я все равно не понимаю.понимание переменных с плавающей запятой

посмотреть на этот код, пожалуйста


<script type="text/javascript"> 
function math(x) 
{ 
var y; 
y = x*10; 
alert(y); 
} 

</script> 
<input type="button" onclick="math(0.011)"> 

Что должно насторожить После нажатия на кнопку? Я думаю 0.11, но нет, это оповещения 0.1099999999999999999 объясните пожалуйста это поведение. Заранее спасибо

+1

ok. Я не знаю почему. но как его решить? – Simon

+1

вы еще не решили проблему. – lincolnk

ответ

5

Это потому, что вы имеете дело с плавающей запятой, и это ожидаемое поведение математики с плавающей запятой.

что вам нужно сделать формат это число.

см. Это java explanation, который также применим здесь, если вы хотите знать , почему это происходит.

in javascript все цифры представлены как 64-битные поплавки, поэтому вы часто сталкиваетесь с такими вещами.

быстрый обзор этой статьи заключается в том, что с плавающей точкой пытается представить диапазон значений больше тогда будет вписываться в 64bits, для этого там будет какой-то неточное представление, и это то, что вы видите.

+0

Я не понимаю – Simon

+5

, что было быстро, вы читали всю статью? – mkoryak

+1

Также см. Http: //en.wikipedia.org/wiki/Floating_point # Accuracy_problems – jball

1

С номером с плавающей запятой вы получаете представление числа, которое вы пытаетесь кодировать. В основном это номер очень закрыть первоначальный номер. Более подробную информацию о кодировании/хранении чисел с плавающей запятой можно найти here.

Примечание: Если вы показываете значение x, оно все равно показывает 0.011, поскольку JavaScript еще не решил, какой тип переменной x имеет. Но после его умножения на 10 тип получил значение с плавающей запятой (это единственная возможность), и отображается круглая ошибка.

1

Вы можете попытаться исправить номер факса десятичных знаков с этим один:

// fl is a float number with some nr of decimals 
// d is how many decimals you want 
function dec(fl, d) { 
    var p = Math.pow(10, d); 
    return Math.round(fl*p)/p; 
} 

Ex:

var n = 0.0; 
console.log(dec(n,6)); // 0.0
console.log(dec(n,5)); // 0.0
console.log(dec(n,4)); // 0.0012 
console.log(dec(n,3)); // 0.001 

Он работает первое умножение поплавка с 10^3 (1000) для трех знаков после запятой, или 10^2 (100) для двух десятичных знаков. Затем сделайте раунд и разделите его на оригинальный размер.
Math.pow(10, d) делает 10^d (означает, что d предоставит нам 1000).

В вашем случае, сделайте alert(dec(y,2));, он должен работать.

+0

нет, не работает. он «ест» вожделение. , но вы мне поможете, мне просто нужно это использовать, посмотрите function dec (fl, d) { var p = Math.pow (10, d); var c = fl * p * 10/p; предупреждение (c); } и когда я называю математику (0.011,3), она работает !!! спасибо – Simon

+0

Так что это не означает «0.11» для вас? Странный. Работает для меня :) функция математика (x) { var y = x * 10; предупреждение (dec (y, 2)); } Функция dec (fl, d) { var p = Math.pow (10, d); return Math.round (fl * p)/p; } математика (0.011); – npup

+0

Ваша функция возвращает 0.01. и это ожидается :) – Simon

9

Ok. Позвольте мне попытаться объяснить это.

Основная вещь, которую следует помнить с числами с плавающей запятой, заключается в следующем: они занимают ограниченное количество бит и пытаются представить исходное число, используя арифметику base-2.

Как известно, в базовых 2 арифметических целых числах представлены степени 2, которые они содержат. Таким образом, 6 будет представлено как 4 + 2, т. Е. в двоичном формате как 110.

Чтобы понять, как представлены дробные числа, вы должны подумать о том, как мы представляем дробные числа в нашей десятичной системе. Дробная часть чисел (например, 0.11) представлена ​​в виде кратных обратных степеней 10 (так как основание равно 10). Таким образом, 0.11 фактически составляет 1/10 + 1/100. Как вы понимаете, это недостаточно мощно, чтобы представлять все дробные числа в ограниченном количестве цифр. Например, 1/3 будет 0,333333 .... в бесконечном порядке. Если бы у нас было всего 32 цифры пробела, чтобы записать число вниз, мы получим только приблизительное значение к исходному числу, 0.3333333333333333333333333333333333. Это число, например, дало бы 0.9999999999999999999999999999999999, если бы оно было умножено на 3, а не 1, как вы ожидали.

Ситуация аналогична в базе-2. Каждое дробное число будет представлено как кратность обратных степеней 2. Таким образом, 0,75 (в десятичной форме) (т. Е. 3/4) будет представлено как 1/2 + 1/4, что будет означать 0.11 (в базе-2). Так же, как база 10 не может достаточно представить каждое дробное число конечным образом, base-2 не может представлять все дробные числа при ограниченном пространстве.

Теперь, попытайтесь представить 0.11 в базе-2; вы начинаете с 11/100 и пытаетесь найти обратную силу 2, которая меньше этого числа. 1/2 не работает, 1/4 нет 1/8. 1/16 подходит для счета, поэтому вы отмечаете 1 на 4-м месте после десятичной точки и вычитаете 1/16 от 11/100. Осталось 19/400. Теперь попробуйте найти следующую мощность 2, которая соответствует описанию. 1/32, кажется, что один, отмечают 5-е место после точки и вычитать 1/32 из 19/400, вы получите 13/800. Затем один 1/64, и вы остались с 1/1600, таким образом, следующий все пути вверх по 1/2048 и т.д. и т.п. Таким образом, мы получили, насколько 0.00011100001, но он идет снова и снова; и вы увидите, что всегда остается остаток. Теперь я не прошел весь расчет, но после того, как вы поместили 32 бинарных цифры после точки, вы, вероятно, по-прежнему будете иметь некоторую долю слева (и это предполагает, что все 32 бита пространства расходуются, представляя десятичную часть, которой это не так). Таким образом, я уверен, что вы можете оценить, что итоговое число может отличаться от его фактической стоимости на какую-то сумму.

В вашем случае разница составляет 0,00000000000000001, что составляет 1/100000000000000000 = 1/10^17, и я уверен, что вы можете понять, почему у вас может быть это.

+0

спасибо большое :) – Simon

+0

Я рад, что это помогло. Удачи. – paracycle

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