Впервые столкнувшись с программированием, хоть на бэкэнде (php), хоть на фронтенде (JavaScript), я столкнулся с проблемой неточности, когда например вместо 2.0 получаешь 1.99999999 или 2.0000001.
Возникает это из-за того, что числа с плавающей точкой не имеют бесконечной точности и где-то там на сороковм знаке после запятой будет или на единичку больше, или на единичку меньше, например, вы делаете
$a=2.4;
А в памяти сохраняется
2.400000000000000000000000000000000001
или наоборот где то на единичку поменьше...
2.399999999999999999999999999999999999999
Если вы, например, округляете копейки в большую сторону, то во втором случае получите 2.40, а в первом 2.41, т.е. клиенту посчитали цену на количество, он на калькуляторе пересчитал, ровно 2.40 посчитал, а тут выводит 2.41, это вызовет негодование, можно и на штрафы нарваться за такое дело...
Самое лучшее решение, которое мной используется уже несколько лет - изначально округлять по математическим законам на один разряд больше нужного, а потом делитьна 10 и округлять до целых в большую сторону...
Например, нам нужно перевести рубли в копейки:
один рубль равен 100 копейкам
21.5 рубль равен 2150 копейкам
Теперь о наших "ущербных" числах, нужно получить до 2х знаков после запятой
2.40000000000001
домножаем на 1000
2400.00000000001
округлим по математическим законам, справа ноль, округлится до
2400
Теперь, делим на 10 и округляем в большую сторону
240
На php такая округлялка будет выглядеть вот так
function float2int2($n,$m):int
{
$n*=pow(10,($m+1));
$n = round($n);
return Ceil($n/10);
}
или так
function float2int2($n,$m):int
{
$n*=pow(10,($m+1));
return Ceil(round($n)/10);
}
Нужно все входные количества дробные округлять и цены, вести все операции с целыми числами, а в самом конце можно выводить деленное на 100 форматированное число из копеек в рубли.
В базе данных лучше использовать такие типы как DECIMAL, там с ограниченной точностью, по сути как целое хранится, только сдвигается запятая на определенное количество знаков.