Форматировать число с плавающей точкой с минимально необходимым количеством десятичных знаков

Я хочу отформатировать число с минимальным количеством знаков после запятой, необходимое для его воспроизведения.

PHP имеет number_format() функция для рендеринга числа с указанным количеством десятичных знаков. Однако, если я использую его для форматирования 0.1 с очень большим количеством десятичных знаков, я получу:

print rtrim(number_format(0.1, 1000, '.', ''), '0');
// 0.1000000000000000055511151231257827021181583404541015625

поскольку (float)"0.1" === 0.1те лишние 55511151... десятичные дроби после позиции 16 бесполезны.

Я могу использовать цикл, как это:

function format_float($float) {
$decimals = 1;
do {
$result = number_format($float, $decimals, '.', '');
$decimals++;
} while ((float)$result !== $float);
return $result;
}

print format_float(0.1) . "\n"; // 0.1
print format_float(1/3) . "\n"; // 0.3333333333333333
print format_float(1E-50) . "\n"; // 0.00000000000000000000000000000000000000000000000001

Но наверняка есть более простой и эффективный способ?

1

Решение

Правильная печать минимального числа десятичных цифр двоичного числа с плавающей запятой очень сложное усилие. Современное состояние семейство алгоритмов грису. Для хорошего объяснения проблем, см. Классическую статью Стил и Уайт.

1

Другие решения

Вот что я придумал:

function format_float($num) {
$dec = $num == 0 ? 0 : ceil(-log10(abs($num)));
$dec = max(1, $dec + 15 /* magic number */);
$res = number_format($num, $dec, '.', '');

// sometimes we need one more decimal
if ((float)$res !== $num) {
$res = number_format($num, $dec + 1, '.', '');
}

list($l, $r) = explode('.', $res, 2);
return "$l." . (rtrim($r) ?: '0');
}

Предполагается, что необходимое количество десятичных знаков будет 15 - log10($num) или же 16 - log10($num), который, кажется, имеет место на практике согласно моим испытаниям. Это по крайней мере более эффективно, чем моя грубая петля силы.

0

По вопросам рекламы [email protected]