Понимание переменных с плавающей запятой
Есть некоторая проблема, я все равно не понимаю.
посмотрите этот код, пожалуйста,
<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,10999999999999999
объясните пожалуйста это поведение.
заранее спасибо
Ответы
Ответ 1
это потому, что вы имеете дело с плавающей точкой, и это ожидаемое поведение математики с плавающей запятой.
что вам нужно сделать, это форматировать это число.
см. это java объяснение, которое также применимо здесь, если вы хотите знать , почему это происходит.
в javascript все числа представлены как 64-битные поплавки, поэтому вы часто сталкиваетесь с такими вещами.
быстрый обзор этой статьи состоит в том, что с плавающей запятой пытается представить диапазон значений больше, тогда он будет входить в 64 бита, поэтому будет некоторое неточное представление, и это то, что вы видите.
Ответ 2
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, и я уверен, что вы можете понять, почему у вас может быть это.
Ответ 3
С номером с плавающей запятой вы получите представление числа, которое вы пытаетесь закодировать. В основном это число, которое очень близко к исходному номеру. Более подробную информацию о кодировании/хранении чисел с плавающей запятой можно найти здесь.
Примечание:
Если вы показываете значение x, оно все равно показывает 0.011, потому что JavaScript еще не решил, какой тип переменной x имеет. Но после его умножения на 10 тип получил значение с плавающей запятой (это единственная возможность), и отображается круглая ошибка.
Ответ 4
Вы можете попытаться исправить nr из десятичных знаков с помощью этого:
// 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;
}
Пример:
var n = 0.0012345;
console.log(dec(n,6)); // 0.001235
console.log(dec(n,5)); // 0.00123
console.log(dec(n,4)); // 0.0012
console.log(dec(n,3)); // 0.001
Он работает, сначала умножая float с 10^3
(1000) на три десятичных знака, или 10^2
(100) на два десятичных знака. Затем сделайте раунд и разделите его на первоначальный размер.
Math.pow(10, d)
делает 10^d
(означает, что d
даст нам 1000).
В вашем случае do alert(dec(y,2));
, он должен работать.