Преобразование float в представление простой строки

ТАК,

Проблема

Мой вопрос о тривиальной вещи: как преобразовать числовую строку в простое («родное») представление. Это означает: если числовая строка уже находится в открытом виде, оставьте ее как есть, но если она находится в научной нотации, преобразуйте ее. Образец:

 "3" -> "3"
 "1,5" -> "1,5"
 "-15.482E-2" -> "-0.15482"

Числовая строка должна быть действительной, а если нет – тогда это не случай преобразования (мы можем, например, возвращать пустую или пустую строку).

Использование регистра

Это необходимо для bcmath потому что он не может работать с научными поплавками. Таким образом, они должны быть преобразованы в простые строки (заданные здесь ). Поэтому важным следствием этого варианта использования является то, что числовая строка может быть чем-то вроде 1E-300 или 1E+500 . Поскольку мы работаем с bcmath – это намерение обрабатывать такие вещи.

Мой подход

На данный момент я реализовал это с помощью regex-almighty , например:

 function parseFloat($string) { $string = (string)$string; if(preg_match('/^[+-]?(\d+|\d+\.\d*)[Ee]([+-]?)(\d+)$/', $string, $matches)) { $precision = false!==($dot=strpos($matches[1], '.')) ?strlen($matches[1])-$dot-1 :0; $precision = $matches[2]=='-' ?$precision + (int)$matches[3] :$precision - (int)$matches[3]; return number_format($string, $precision<0?0:$precision, '', ''); } if(preg_match('/^[+-]?(\d+|\d+\.\d+)$/', $string)) { return $string; } } 

Вопрос

Я чувствую, что должен быть более простой и мудрый способ сделать это. Как добиться этого более простым способом в PHP? Может быть, какой-то сложный формат sprintf() ?

Важное замечание : я не хочу иметь дело с точностью. Я хочу черный ящик. Передайте что-то числовое – получите строку в качестве вывода. Это все. Не хочу иметь дело ни с чем другим. На самом деле, все мое регулярное выражение – это вычисление длины и точности – так что, конечно, если передать их явно (как параметры, например), мы избавимся от регулярного выражения. Но – нет, это не то, что я хочу.

Поскольку sprintf() с "%.f" имеет проблемы с выражениями, такими как "1e-8" , может потребоваться некоторая обработка текста:

 function convertFloat($floatAsString) { $norm = strval(floatval($floatAsString)); if (($e = strrchr($norm, 'E')) === false) { return $norm; } return number_format($norm, -intval(substr($e, 1))); } 

Протестировано с помощью:

 3 3 1.5 1.5 -15.482e-2 -0.15482 1e-8 0.00000001 1e+3 1000 -4.66E-2 -0.0466 3e-3 0.003 
 # convert output of used php-math functions like sin in scientific notation to decimal notation function xpnd($scientific, $precision){ # expand from scientific notation if(is_int($scientific)){ #don't convert integers return $scientific; } return sprintf("%.".$precision."F", $scientific); } 

Где $ precision – желаемое количество дробных цифр.

Для тех, кто просто хочет конвертировать float в строку.

 function float_to_string($float) { $string = (string)$float; if (preg_match('~\.(\d+)E([+-])?(\d+)~', $string, $matches)) { $decimals = $matches[2] === '-' ? strlen($matches[1]) + $matches[3] : 0; $string = number_format($float, $decimals,'.',''); } return $string; } $float = 0.00000000020001; echo $float; // 2.0001E-10 echo PHP_EOL; echo float_to_string($float); // 0.00000000020001 echo PHP_EOL; $float = 10000000000000000000000; echo $float; // 1.0E+22 echo PHP_EOL; echo float_to_string($float); // 10000000000000000000000 echo PHP_EOL; 

(Обновлено для использования non-depreciated функций, предложенных andufo, я выбрал explode, но вы можете использовать preg_split если хотите. В качестве побочной заметки, если кто-то все еще читает это, принятый ответ терпит неудачу – попробуйте его с моим первым и последним прецедент.)

Я выкопал небольшой драгоценный камень из досок PHP, опубликованных benjcarson в 2002 году, который отметил вашу точную проблему с bcmath и научной нотацией

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

 function exp2int($exp) { list($mantissa, $exponent) = explode("e", strtolower($exp)); if($exponent=='') return $exp; list($int, $dec) = explode(".", $mantissa); bcscale (abs($exponent-strlen($dec))); return bcmul($mantissa, bcpow("10", $exponent)); } 

В качестве побочного примечания ваш исходный код выходит из строя на любых номерах, меньших 1E-40

(Как и все текущие ответы, используя sprintf)

Было бы легче отладить, если бы вы разместили больше своих тестовых примеров, но это работает для всего, что вы опубликовали до сих пор

Тестовые случаи:

 echo exp2int("-1.82235135978667123456789E5"); \\-182235.135978667123456789 echo exp2int("1.1350865232E-60"); \\0.0000000000000000000000000000000000000000000000000000000000011350865232 echo exp2int("-15.482E-2"); \\-0.15482 echo exp2int("1.5"); \\1.5 echo exp2int("3"); \\3 echo exp2int("123.123e10"); \\1231230000000.000 - you mentioned trailing 0's aren't a problem echo exp2int("123.123e-10"); \\0.0000000123123 echo exp2int("123456789E-9"); \\0.123456789 echo exp2int("12345.6789E-5"); \\0.123456789 echo exp2int("1E-300"); \\0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001