Неожиданное решение.

BeGe

Вождь Апачей, блин (c)
Неожиданное решение.

Задача посталвеная Ильёй Альшанетским

http://ilia.ws/archives/67-PHP-Floating-Point-Math.html

PHP:
<?php

$a = 1.8432432;
while ((int)$a != $a) $a *= 10;

?>
Один из вариантов решение бага....

PHP:
<?php
$a = 1.8432432;
while (strlen($a) != strlen(intval($a))) {
$a *= 10;
}
?>
 

sage

Новичок
это не один из вариантов, это точно такой же вариант
 

BeGe

Вождь Апачей, блин (c)
А ты уверен что первый на 100% работает ? :)
Проверял ?
тестированно на php 4.3.11
 

Mihail

Guest
PHP:
<?php
  $a = 1.8432432;
  echo $a."\n";
  $a=str_replace(".","",$a);
  echo $a."\n";
?>
 

BeGe

Вождь Апачей, блин (c)
Мдя.... ребята учебник по информатике в руках держали хоть раз ?
Это кусок классического алгоритма.

А проблема в том что - если ты работаешь с флоат то ты получаешь всегда или
12.999999999 или 13.000000001
 

BeGe

Вождь Апачей, блин (c)
ForJest мне пожалуйста что бы работало нормально с типом флоат :). если я обявляю 12.4567 - то что бы оно считало только 4 знака после запятой :)
 

Domovoj

Guest
Автор оригинала: BeGe
ForJest мне пожалуйста что бы работало нормально с типом флоат :). если я обявляю 12.4567 - то что бы оно считало только 4 знака после запятой :)
А при чём здесь PHP? Тебе же предложили использовать str_replace()... Вот и используй её, а потом переводи тип в float...
 

Mihail

Guest
Если говорить о числах с павающей запятой, необходимо определиться с точностью результат.
Вот это работает.

<?php
$a = 1.8432432;
while ( bccomp((int)$a,$a,7) != 0) {
$a*=10;
}
echo $a."\n";
?>

Из manuala:

Точность числа с плавающей точкой

Довольно часто простые десятичные дроби вроде 0.1 или 0.7 не могут быть преобразованы в свои внутренние двоичные аналоги без небольшой потери точности. Это может привести к неожиданным результатам: например, floor((0.1+0.7)*10) скорее всего возвратит 7 вместо ожидаемой 8 как результат внутреннего представления числа, являющегося в действительности чем-то вроде 7.9999999999....

Это связано с невозможностью точно выразить некоторые дроби в десятичной системе счисления конечным числом цифр. Например, 1/3 в десятичной форме принимает вид 0.3333333. . ..

Так что никогда не доверяйте точности последних цифр в результатах с числами с плавающей точкой и никогда не проверяйте их на равенство. Если вам действительно необходима высокая точность, вам следует использовать математические функции произвольной точности или gmp-функции.
 

SiMM

Новичок
> если я обявляю 12.4567 - то что бы оно считало только 4 знака после запятой :)
Приведённый вами же вариант решения данную проблему никоим образом не решает.
PHP:
$a = 1.84324321154;
 

Mihail

Guest
<?php

function zzz($a1,$a2=1) {
$b = fmod($a1,1);
$c = $a1-$b;
$cnt=0;
$i=$b;
while (1==1) {
if ( fmod(round($i,$a2),1) == round(0,$a2) ) break;
$i *=10;
$cnt++;
}
$result= $c*pow(10,$cnt)+round($i,$a2);
return $result;
}

$a = 1.8432432;
echo zzz($a)."\n";

$a = 1.8432432124;
echo zzz($a)."\n";

$a=12.4567;
echo zzz($a)."\n";

$a=121342.421347;
echo zzz($a)."\n";


?>
 

SiMM

Новичок
PHP:
$a = 1.01; // какой смысл в round(0,$a2) - науке неизвсетсно
 

Mihail

Guest
Перестраховка!

На самом деле хоть var_dump() не выводит никаких значений, но
вероятно 0 может быть равен 0.0000000000000000993.

Говорю сразу не проверял.

Для этого надо смотреть исходный код PHP.

Аналогичный пример сравнения есть на php.net функция round().

Там, заодно, есть описание всех глюков PHP с представением чисел в float формате.

С $a = 1.01; все поняно - увелич значение $a2.
 

SiMM

Новичок
> С $a = 1.01; все поняно - увелич значение $a2.
Это называется танцы с бубном :) И потом, наш классик информатики вполне мог бы тебе предложить пример
PHP:
$a = 1.00000000000001;
echo zzz($a,20)."\n";
var_dump($a-1);
> вероятно 0 может быть равен 0.0000000000000000993.
Это что-то уж совсем невероятное за гранью фантастики. ИМХО. Насколько я помню - ноль - это ноль. А не просто очень малая величина.
 

Mihail

Guest
Никаких танцев.

float round ( float val [, int precision] )
$a2- Это точность
$a = 1.01 нужна точность 2 знака после запятой , а по умолчанию 1.

Не нравится round(0,$a2) поставте 0 и флаг вам в руки.
Я уже писал про PHP и float выше.

Не забудте, что тип int всего 10 знаков.

$a = 1.00000000000001;
echo zzz($a,14)."\n";

The size of a float is platform-dependent, although a maximum of ~1.8e308 with a precision of roughly 14 decimal digits is a common value (that's 64 bit IEEE format).


function zzz($a1,$a2=1) {
$b = fmod($a1,1);
$c = $a1-$b;
$cnt=0;
$i=$b;
while (1==1) {
if ( fmod(round($i,$a2),1) == round(0,$a2) ) break;
$i *=10;
$i=round($i,$a2); // добавил сюда округление
echo $i."\n";
$cnt++;
}
$result= $c*pow(10,$cnt)+round($i,$a2);
return $result;
}

-~{}~ 23.08.05 10:01:

Сорри, тоже работает через раз.
Смотрю исходники PHP:

#ifndef PHP_ROUND_FUZZ
# ifndef PHP_WIN32
# define PHP_ROUND_FUZZ 0.50000000001
# else
# define PHP_ROUND_FUZZ 0.5
# endif
#endif

#define PHP_ROUND_WITH_FUZZ(val, places) { \
double tmp_val=val, f = pow(10.0, (double) places); \
tmp_val *= f; \
if (tmp_val >= 0.0) { \
tmp_val = floor(tmp_val + PHP_ROUND_FUZZ); \
} else { \
tmp_val = ceil(tmp_val - PHP_ROUND_FUZZ); \
} \
tmp_val /= f; \
val = !zend_isnan(tmp_val) ? tmp_val : val; \
} \


/* {{{ proto float round(float number [, int precision])
Returns the number rounded to specified precision */
PHP_FUNCTION(round)
{
zval **value, **precision;
int places = 0;
double return_val;

if (ZEND_NUM_ARGS() < 1 || ZEND_NUM_ARGS() > 2 ||
zend_get_parameters_ex(ZEND_NUM_ARGS(), &value, &precision) == FAILURE) {
WRONG_PARAM_COUNT;
}

if (ZEND_NUM_ARGS() == 2) {
convert_to_long_ex(precision);
places = (int) Z_LVAL_PP(precision);
}

convert_scalar_to_number_ex(value);

switch (Z_TYPE_PP(value)) {
case IS_LONG:
/* Simple case - long that doesn't need to be rounded. */
if (places >= 0) {
RETURN_DOUBLE((double) Z_LVAL_PP(value));
}
/* break omitted intentionally */

case IS_DOUBLE:
return_val = (Z_TYPE_PP(value) == IS_LONG) ?
(double)Z_LVAL_PP(value) : Z_DVAL_PP(value);

PHP_ROUND_WITH_FUZZ(return_val, places);

RETURN_DOUBLE(return_val);
break;

default:
RETURN_FALSE;
break;
}
}

-~{}~ 23.08.05 10:03:

файл \ext\standart\math.c

-~{}~ 23.08.05 10:12:

Всем кому интересна проблема с мат. операциями в PHP, сюда:

http://www.zend.com/lists/php-dev/200407/msg00651.html
 
Сверху