Форум: Форум PHPФорум ApacheФорум Регулярные ВыраженияФорум MySQLHTML+CSS+JavaScriptФорум FlashРазное
Новые темы: 0000000
MySQL 5. В подлиннике. Авторы: Кузнецов М.В., Симдянов И.В. C++. Мастер-класс в задачах и примерах. Авторы: Кузнецов М.В., Симдянов И.В. Самоучитель MySQL 5. Авторы: Кузнецов М.В., Симдянов И.В. Программирование. Ступени успешной карьеры. Авторы: Кузнецов М.В., Симдянов И.В. Социальная инженерия и социальные хакеры. Авторы: Кузнецов М.В., Симдянов И.В.
ВСЕ НАШИ КНИГИ
Консультационный центр SoftTime

Форум PHP

Выбрать другой форум

 

Здравствуйте, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: сумма прописью
 
 автор: alex195   (20.02.2007 в 13:10)   письмо автору
 
 

в открытом доступе попадается скрипт: http://sitemonitor.ru/webdev/php/sum.php
который считает сумму прописью, но иногда выдает ошибку!
И как ее забороть пока ума не приложу... может кто советом поможет.

При вводе числа "8192.8"
пишет "восемь тысяч сто девяносто два рубля семьдесят девять копеек"

а при вводе "8191.8"
"восемь тысяч сто девяносто один рубль восемдесят копеек"



<?
$_1_2
[1]="одна ";
$_1_2[2]="две ";

$_1_19[1]="один ";
$_1_19[2]="два ";
$_1_19[3]="три ";
$_1_19[4]="четыре ";
$_1_19[5]="пять ";
$_1_19[6]="шесть ";
$_1_19[7]="семь ";
$_1_19[8]="восемь ";
$_1_19[9]="девять ";
$_1_19[10]="десять ";
$_1_19[11]="одиннацать ";
$_1_19[12]="двенадцать ";
$_1_19[13]="тринадцать ";
$_1_19[14]="четырнадцать ";
$_1_19[15]="пятнадцать ";
$_1_19[16]="шестнадцать ";
$_1_19[17]="семнадцать ";
$_1_19[18]="восемнадцать ";
$_1_19[19]="девятнадцать ";

$des[2]="двадцать ";
$des[3]="тридцать ";
$des[4]="сорок ";
$des[5]="пятьдесят ";
$des[6]="шестьдесят ";
$des[7]="семьдесят ";
$des[8]="восемдесят ";
$des[9]="девяносто ";

$hang[1]="сто ";
$hang[2]="двести ";
$hang[3]="триста ";
$hang[4]="четыреста ";
$hang[5]="пятьсот ";
$hang[6]="шестьсот ";
$hang[7]="семьсот ";
$hang[8]="восемьсот ";
$hang[9]="девятьсот ";

$namerub[1]="рубль ";
$namerub[2]="рубля ";
$namerub[3]="рублей ";

$nametho[1]="тысяча ";
$nametho[2]="тысячи ";
$nametho[3]="тысяч ";

$namemil[1]="миллион ";
$namemil[2]="миллиона ";
$namemil[3]="миллионов ";

$namemrd[1]="миллиард ";
$namemrd[2]="миллиарда ";
$namemrd[3]="миллиардов ";

$kopeek[1]="копейка ";
$kopeek[2]="копейки ";
$kopeek[3]="копеек ";


function 
semantic($i,&$words,&$many,$f)
{
global 
$_1_2$_1_19$des$hang$namerub$nametho$namemil$namemrd;
// в words будем пихать запись числа
$words="";
$fl=0;
//рассматриваем промежуток чисел от 100 до 999
if($i >= 100)
{
  
//сколько сотен
  
$jkl intval($i 100);
  
$words.=$hang[$jkl];
  
//отбрасываем "сотенный разряд" и считаем остальные разряды
  
$i%=100;
}
//рассматриваем промежуток чисел от 20 до 10 (от 20, потому что есть
//всякие одиннадцать, двенадцать...)
if($i >= 20)
{
  
$jkl intval($i 10);
  
$words.=$des[$jkl];
  
//отбрасываем рязряд десятков и остаемся с маленьким числом от 1 до 9
  
$i%=10;
  
$fl=1;
}

//в $fem - индекс массива с записью чисел
switch($i)
{
  case 
1$many=1; break;
  case 
2:
  case 
3:
  case 
4$many=2; break;
  default: 
$many=3; break;
}

//если тысяча, то одна или две, а если нет, то один или два...
if($i)
{
  if(
$i && $f == 1)
   
$words.=$_1_2[$i];
  else
   
$words.=$_1_19[$i];
}
}

function 
num2str($L)
{
global 
$_1_2$_1_19$des$hang$namerub$nametho$namemil$namemrd$kopeek;

$s=" ";
$s1=" ";
//считаем количество копеек, т.е. дробной части числа
$kop=intval(( $L*100 intval($L)*100 ));
//отбрасываем дробную часть
$L=intval($L);

if(
$L>=1000000000)
{
  
$many=0;
  
semantic(intval($L 1000000000),$s1,$many,3);
  
$s.=$s1.$namemrd[$many];
  
$L%=1000000000;
  
//если ровно сколько-то миллиардов, то хватит считать
  
if($L==0)
  {
   
$s.="рублей ";
  }
}

if(
$L >= 1000000)
{
  
$many=0;
  
semantic(intval($L 1000000),$s1,$many,2);
  
$s.=$s1.$namemil[$many];
  
$L%=1000000;
  
//аналогично если ровно сколько-то миллионов, то хватит считать
  
if($L==0)
  {
   
$s.="рублей ";
  }
}

if(
$L >= 1000)
{
  
$many=0;
  
semantic(intval($L 1000),$s1,$many,1);
  
$s.=$s1.$nametho[$many];
  
$L%=1000;
  if(
$L==0)
  {
   
$s.="рублей ";
  }
}


if(
$L != 0)
{
  
$many=0;
  
semantic($L,$s1,$many,0);
  
$s.=$s1.$namerub[$many];
}

//если есть копейки, то добавим их в итоговую строку
if($kop 0)
{
  
$many=0;
  
semantic($kop,$s1,$many,1);
  
$s.=$s1.$kopeek[$many];
}
else
{
  
$s.=" 00 копеек";
}

return 
$s;
}

if (!isset(
$per))
{
?>
<FORM ACTION ="<? echo $PHP_SELF?>">
Введите положительное число, меньшее 10<sup>6<br>
<INPUT type="text" name="per"><BR>
<INPUT type="submit" value="Отправить">
</FORM>
<?
}
else echo 
num2str($per);

?> 

   
 
 автор: cheops   (20.02.2007 в 13:11)   письмо автору
 
   для: alex195   (20.02.2007 в 13:10)
 

Возможно вас заинтересует тема по ссылке http://www.softtime.ru/forum/read.php?id_forum=1&id_theme=4540

   
 
 автор: alex195   (20.02.2007 в 13:16)   письмо автору
 
   для: cheops   (20.02.2007 в 13:11)
 

Это несколько не то....
очень хотелось бы найти ошибку в этом скрипте

   
 
 автор: trix   (20.02.2007 в 19:59)   письмо автору
 
   для: alex195   (20.02.2007 в 13:16)
 

Тут какая то не понятная проблема с вычитанием этих цифр, даже элементарно если сделать


$l = 8192.8;
$t = 8192;
$z = $l - $t;

print "Z - $z";


Результат будет неожиданный :)
Z = 0.79999999999927

Поэтому вместо $kop = intval....
Можно попробывать вырезать 2 цифры после знака пунктуации, если последняя цифра 8192.8 одна восьмерка, то допишем к ней 0 чтобы было 80:


$point = strpos($L,".",0)+1;
$kop = substr($L,$point,2);
$count = strlen($kop);
if($count == 1)
{
$kop .= 0;
}

   
 
 автор: alex195   (21.02.2007 в 08:55)   письмо автору
 
   для: trix   (20.02.2007 в 19:59)
 

Да, именно с тем же и я столкнулся.....
толи это у нас аппаратные глюки - сам компьютер производит вычисления с ошибкой
либо это в PHP чего-то не так...

Большое спасибо за конкретное предложенное решение проблемы, но может все-таки удастся докопаться до истины?
Теоретически применение команды intval вполне логично, сам еще в 90-х на бейсике пользовался функцией VAL(), чтобы выделять дробную часть из числа.
Надо посмотреть - может еще есть какие-нибудь функции, которые более корректно заменят intval.

   
 
 автор: Trianon   (21.02.2007 в 10:08)   письмо автору
 
   для: alex195   (21.02.2007 в 08:55)
 

Нету у Вас никаких глюков.
Есть такое понятие, как точность вычислений.
Вас же не смущает, что число "одна третья" или "одна седьмая", Вы не можете записать с абсолютной точностью?
Точно также компьютер не в состоянии записать число "одна десятая", поскольку числа хранит в двоичной, а не десятичной системе.

Если хотите оперировать точными денежными велечинами - множьте сумму на сто, переводя в копейки, а затем отделяйте два последних разряда.

   
 
 автор: trix   (21.02.2007 в 14:37)   письмо автору
 
   для: Trianon   (21.02.2007 в 10:08)
 

В данном случае умножение на 100 не помогает.



$l = 8192.8;
$t = 8192;
$z = $l*100 - $t*100;



Z = 79.999999999884 =)

Попробуйте сами ради интереса, главное такой прикол токо с этими цифрами :)

   
 
 автор: Trianon   (21.02.2007 в 14:50)   письмо автору
 
   для: trix   (21.02.2007 в 14:37)
 

Еще раз. Если Вы полагаете, что написав $l = 8192.8; Вы загнали в переменную $l "число 8192 и четыре пятых ровно" , то Вы сильно заблуждаетесь.
Просто потому, что четыре пятых в двоичной системе счисления (в которой хранятся числа) представляются в виде бесконечной периодической дроби. 0.1100110011001100..... и т.д.


0.8*2=
.--------
1.6*2= 
1.2*2=
0.4*2=
0.8*2=
1.6*2=


Такой прикол будет с любыми "цифрами", если в знаменателе не окажется степень двойки

   
 
 автор: alex195   (22.02.2007 в 07:27)   письмо автору
 
   для: Trianon   (21.02.2007 в 14:50)
 

Какой же выход?
В принципе я не смог найти еще числа, которые приводят к такому глюку, но исключить его необходимо...

   
 
 автор: Ziq   (22.02.2007 в 08:09)   письмо автору
 
   для: alex195   (22.02.2007 в 07:27)
 

Попробуйте воспользоваться вот этим http://ru.php.net/manual/ru/ref.bc.php


$l = 8192.8;
$t = 8192;
echo bcsub($l, $t, 2);

   
Rambler's Top100
вверх

Rambler's Top100 Яндекс.Метрика Яндекс цитирования