Ответ 1
Как указано Quentin, это проблема с плавающей точкой IEEE.
0.1
фактически не существует в десятичной плавающей запятой технически просто из-за того, как работает двоичный файл.
0.1
- одна десятая, или 1/10. Чтобы показать его в двоичном формате, разделите двоичный код 1 на двоичный код 1010, используя двоичное длинное деление:
Как вы можете видеть, 0.1
в двоичном формате 0.0001100110011....0011
, и он будет продолжать повторять 0011
в конце до бесконечности.
Браузеры выбирают ближайшую доступную точку для 0.1
и используют ее как непрозрачность. Некоторые перейдут, а некоторые подойдут.
FireFox я бы догадался, что он просто показывает читаемую человеком версию, но на самом деле ее действительно использует плавающую точку, пригодную для использования компьютером.
В качестве примера:
body {
color: rgba(0,0,0,0.1); // actually 0.0980392
opacity: 0.1; // actually 0.100000001490116
}
Два совершенно разных значения для одной и той же точки с плавающей запятой.
Эта проблема с плавающей запятой действительно может быть реплицирована в другом месте в браузерах, используя другие языки, такие как Javascript. Номера Javascript всегда 64-битные с плавающей запятой (что, я считаю, CSS тоже). Это более широко известно как плавающая точка с двойной точностью. PHP также использует плавающие точки с двойной точностью.
64-битные числа с плавающей запятой, как вы могли догадаться, хранились в 64 битах, где число (дроби) хранится в битах от 0 до 51, показатель в битах 52-62 и знаковый бит 63.
Это вызывает проблемы в строке, так как это означает, что целые числа считаются точными до 15 десятичных точек и могут действительно вычислять до 17 десятичных точек.
Это означает, что числа могут округляться очень легко или просто не могут быть сохранены правильно.
var x = 999999999999999; // x = 999999999999999
var y = 9999999999999999; // y = 10000000000000000
Арифметика для плавающих точек также может быть вне выравнивания довольно много в местах. Как я показал выше; 0.1
в десятичном значении не актуально 0.1
, но 0.000110011...
и т.д. Это означает, что некоторые основные математические данные могут быть совершенно неправильными.
var x = 0.2 + 0.1; // x = 0.30000000000000004
В итоге вам придется запутать систему, чтобы получить нужный номер. Это можно сделать *
числом 10
и затем делить его, чтобы получить ваш фактический желаемый результат.
var x = (0.2 * 10 + 0.1 * 10) / 10; // x = 0.3
Точность в плавающей точке компьютеров очень сложна и еще сложнее, когда существует множество различных реализаций (или браузеров), пытающихся сделать все возможное для скорости и отображения информации, которую они получили правильно.
Существует довольно много разных частей информации о плавающих точках и то, что может пытаться достигнуть процессор CSS (или JS, как я ожидаю, будут вычисления одинаковыми).