Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > PHP: Общие вопросы > Калькулятор на PHP


Автор: Osrus 16.12.2004, 03:44
Наврняка кто-нибудь писал таковой, если простой какой-нибудь есть, покажите код, интересно как это выглядит

Автор: Secandr 16.12.2004, 14:30
Калькулятор на php - изврат, тебе придётся перегружать каждый раз страничку.

Есть смысл писать калькулятор на jsvsscript.

Автор: Black 16.12.2004, 14:51
Можно с помощью нуль фрейма передавать данные и при помощи JavaScript выводить данные в <div></div>

Однако, как сказал Secandr калькултор на PHP - это полное извращение над человечеством :-)

Автор: Sardar 16.12.2004, 16:54
Да ладно в консоли запустил и вперёд. Только зачем оно нужно?

Автор: Рыжий 16.12.2004, 17:23
Я например когда писал то просто делал 2 страници, на одной я размещал формы для заполнения, а на второй сам скрипт и все
PS обращался я к переменным при помощи их имен в параметре
<input type=text name="name">

Автор: sergejzr 16.12.2004, 17:28
А зачем? Ведь есть Google smile
А msn даже уравнения вырешивает smile

Автор: Рыжий 16.12.2004, 17:38
Кстати вот нашел код если что не понятно - пиши:

Код

<html><body>
<form action=hello.php>
Введите 1 число:
<input type=text name="first"><br>
Введите 2 число:
<input type=text name="second" ><br>
<input type=submit value="+">
</body></html>


Этот файл сохрани как хочешь, а следующий - hello.php Вот он:

Код

<html><head>
<title>hello</title>
</head><body>
<?php
$a=0;
$a=$first+$second;
echo "Сумма вышла $a";
?>
</body>
</html>


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

Автор: Sardar 17.12.2004, 00:46
Это совсем никуда, калькулятор должен разбирать выражения. Это не сложно smile

Автор: sergejzr 17.12.2004, 00:50
Вот кстати, как должен он работать smile
http://beta.search.msn.com/results.aspx?q=3*x%5E2%3D6&FORM=QBHP

Только мелкомягкие вообще математику не уважают smile надо же было додуматься написать такой ответ smile smile

Автор: penizillin 17.12.2004, 04:04
чем он неверен? 6 знаков после запятой вам мало?

Автор: sergejzr 17.12.2004, 04:44
Цитата(penizillin @ 17.12.2004, 03:04)
6 знаков после запятой вам мало?

Нет, мне другое глаз режет.
Вот за такие знаки "=" ставят две двойки с минусом в четвёртом классе средней школы smile

Цитата
3* x^2=6 = x=-1.414214 x=1.414214

Автор: penizillin 17.12.2004, 05:08
это да.

Автор: Наставник 17.12.2004, 07:24
Кстати, господа, если уж зашла речь, а как на Ваш взгляд проще разбирать выражения -- что использовать бин. деревья, или теорию конечных автоматов. Мне было бы интересно послушать ответы, просто делал как-то такое сам (конечно не на php, но все же) и как-то честно признаюсь фигово это все работало.

Автор: Secandr 17.12.2004, 09:20
не деревья не теорию автоматов не знаю smile но парсер написать можно... там насколько я понимаю нужно выставить приоритеты в выражениях, основная проблема со скобками.

Автор: Наставник 17.12.2004, 17:40
Вот так и я делал, в лоб - разбирал, приоритеты выставлял и со скобками мучился... но потом меня попросили, чтобы этот парсер ещё мог разбирать и тригонометрические выражения, всего-то шесть sin, cos и т. д. и вот мне тут настала полная ж**а, т.к. тяжело было вносить изменения в уже существующий код...

Автор: Pilgrim Anton 17.12.2004, 17:55
Можно использовать конечные состояния вместе с рекурсией.
В принципе это – не особо сложно. Рекурсия разбивает выражение на атомы, а с атомами работают конечные состояния.

Автор: Наставник 17.12.2004, 18:01
quote=Pilgrim Anton, 17.12.2004, 17:55]Рекурсия разбивает выражение на атомы, а с атомами работают конечные состояния[/quote]
Это что-то типа "Разделяй и властвуй" - хм, кстати может быть и замечательная идея...

хм, хотелось бы узнать, как с помощью рекурсии разбивать выражения на атомы, я понимаю там быстрая сортировка или подсчет факториала, когда данные однородные, но в данном случае данные не одного формата (числа, скобки и sin, cos ...)

Автор: Pilgrim Anton 17.12.2004, 18:14
Наставник
Для начала нужно сформулировать что есть атом. Когда это станет понятно, то, думаю дальше пойдет легче.

Еще идея: можно проставить недостающие скобки - это и будет разбиением на атомы.

Автор: Наставник 17.12.2004, 18:21
Хм, может оно верно

Цитата(Pilgrim @ 17.12.2004, 18:14)
Для начала нужно сформулировать что есть атом


но, как-то не могу выделить атом из потока данных.

Цитата(Pilgrim @ 17.12.2004, 18:14)
Еще идея: можно проставить недостающие скобки - это и будет разбиением на атомы.


К сожалению не понял, что Вы хотели этим сказать.

А вообще чтобы не просто так говорить, лучше на примере всё это объснять, вот допустим очень простое выражение

2+(cos(34*6)+80 - (25^3))*11.5+((34/5-8)+exp(4*2+90))

Какие есть идеи?

Автор: Pilgrim Anton 17.12.2004, 18:32
Давайте разберем пример попроще: 3+6/8*cos(4+6*2)
Итак, 3+6/8*cos(4+6*2)= (3+((6/8)*(cos((4+(6*2))))))

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

Автор: Наставник 17.12.2004, 18:42
Цитата(Pilgrim @ 17.12.2004, 18:32)
Итак, 3+6/8*cos(4+6*2)= (3+((6/8)*(cos((4+(6*2))))))


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

итак 3+6/8*cos(4+6*2) - можно вот с этим выражением повозиться, кроме анализатора, не представляю возможности как это можно было бы посчитать.

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

Добавлено @ 18:46
это по поводу тупого анализатора -

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

Автор: Pilgrim Anton 17.12.2004, 18:47
Атомом первого рода будем считать:
число.
Атомом второго рода будем считать:
1) любой оператор L(a, b), где a, b - атомы первого рода (Например: +(2, 3)=2+3);
2) любой оператор L(a) , где а - атом первого рода (например: Cos(90))

Выражением будем считать:
Оператор L(a, b), где
1) a - атом первого рода, b -атом второго рода
2) a - атом второго рода, b -атом первого рода
3) a - атом второго рода, b -атом второго рода
4) a или b - выражение
Оператор L(a), где
1) а - атом второго рода
2) а - выражение

Это - разбивка на атомы и выражения.
Скобки нужны для разбивки на атомы, хотя над этим стоит еще подумать smile

Автор: Наставник 17.12.2004, 18:50
Хм, в теории более мение понятно... хотя конечно лучше на практическом примере.
Добавлено @ 18:58
Вот пример польской нотации..
(a*(c+d)+(e+f)*g)/(j+i)
получим
/+*a+cd*+efg+ji
а в обратной польской нотации
acd+*ef+g*+ji+/

а вот очень простой пример

допустие есть выражение
a*b+c
Переводим в обратную польскую нотацию, получаем
ab*c+

--->
ВЫПОЛНЕНИЕ

загрузить a в аккумулятор A1
поместить в стек содержимое A1
загрузить b в аккумулятор A1
поместить в стек содержимое A1
извлечь из стека и поместить в аккумулятор A2
извлечь из стека и поместить в аккумулятор A1
выполнить умножение
поместить в стек содержимое A1
загрузить c в аккумулятор A1
поместить в стек содержимое A1
извлечь из стека и поместить в аккумулятор A2
извлечь из стека и поместить в аккумулятор A1
выполнить умножение





Автор: Pilgrim Anton 17.12.2004, 19:06
Цитата
Обратная польская нотация

Наиболее простая система записи математических выражений для электронной обработки - обратная польская нотация. Например, выражение "(a + b)*(c - d)/sin(e)" в этой системе записывается как "a b + c d - * e sin /". В этой системе не нужны скобки. и все выражения могут быть вычислены с помощью простого алгоритма, использующего стек. Когда при проходе строки встречается переменная, она помещается в стек, а когда встречается знак математической операции, из стека извлекается нужное количество переменных, осуществляется операция и результат снова помещается в стек. Когда вся строка пройдена, остается лишь извлечь из стека результат (если формула была записана правильно, то это будет единственный элемент стека).

Перевод традиционной формы записи математических выражений в ОПН - немного более сложная операция. Она также осуществляется с использованием стека, но теперь это стек математических операций. Приоритете математических операций таков:

  1. Функции (напр. sin, cos) и скобки
  2. Умножение и деление
  3. Сложение и вычитание

Алгоритм перевода таков:

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

Цитата с сайта http://mathmatrix.narod.ru/AlgorR.html

Надо попробовать будет

Автор: Наставник 17.12.2004, 19:10
Насчет обратной польской записи я привел в ДОПОЛНЕНИЕ пример..
Добавлено @ 19:12
А вообще классная статья. (поставил бы +, да не могу.)

Автор: Secandr 18.12.2004, 09:19
Да интересная статья, повысил репутацию.

Автор: EXTR 19.12.2004, 01:55
Исходник на JS, может понадобится.

Код

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
 <title>Êàëüêóëÿòîð</title>
 <meta http-equiv="Content-Type" content="text/html; charset=windows-1251;" />
 <style type="text/css">
  .i_button{width: 30px}
 </style>
 <script type="text/javascript">
 
   var str_value="";
   var new_value="";
   var button="";
   function s_write(new_value)
   {
      str_value+=new_value;
      document.getElementById('txt_field').value=str_value;
   }
   function clean()
   {
      str_value="";
      document.getElementById('txt_field').value=str_value;
   }
   function calculate()
   {
      str_value=document.getElementById('txt_field').value;
      str_value=eval(str_value);
      if(str_value==undefined)
      {
         alert("Ïîæàëóéñòà, ââåäèòå âàøå âûðàæåíèå, à çàòåì íàæìèòå íà êíîïî÷êó \"Ââîä\"");
         str_value="";
         return false;
      }
      if(str_value==Infinity)
      {
        str_value="Áåñêîíå÷íîñòü";
      }
      document.getElementById('txt_field').value=str_value;
      return false;
   }
 </script>
</head>
<body style="background-color: #cccccc;" onLoad="calc.txt_field.focus();">
 <h2 style="text-align: center; font-family: Verdana, sans-serif; color: Darkred;">Êàëüêóëÿòîð</h2>
 <form name="calc" onSubmit="return calculate();">
  <table cllpadding="10" cellspacing="0" border="0" align="center" style="text-align: center; background-color: #ffffff; ">
   <tr>
    <td colspan="4"><input type="text" length="20" maxlength="20" id="txt_field" style="background-color: #f4f4f4; text-align: right;" value=" " readonly=\"true\" /></td>
   </tr>
   <tr>
    <td><input type="button" class="i_button" value="/" onClick="s_write(this.value);" /></td>
    <td><input type="button" class="i_button" value="*" onClick="s_write(this.value);" /></td>
    <td><input type="button" class="i_button" value="-" onClick="s_write(this.value);" /></td>
    <td><input type="button" class="i_button" value="C" style="width: 50px; color: Darkred; font-weight: bold;" onClick="clean();" /></td>
   </tr>
   <tr>
    <td><input type="button" class="i_button" value="7" onClick="s_write(this.value);" /></td>
    <td><input type="button" class="i_button" value="8" onClick="s_write(this.value);" /></td>
    <td><input type="button" class="i_button" value="9" onClick="s_write(this.value);" /></td>
    <td rowspan="2"><input type="button" name="plus" value="+" style="width: 50px; height: 50px;" onClick="s_write(this.value);" /></td>
   </tr>
   <tr>
    <td><input type="button" class="i_button" value="4" onClick="s_write(this.value);" /></td>
    <td><input type="button" class="i_button" value="5" onClick="s_write(this.value);" /></td>
    <td><input type="button" class="i_button" value="6" onClick="s_write(this.value);" /></td>
   </tr>
   <tr>
    <td><input type="button" class="i_button" value="1" onClick="s_write(this.value);" /></td>
    <td><input type="button" class="i_button" value="2" onClick="s_write(this.value);" /></td>
    <td><input type="button" class="i_button" value="3" onClick="s_write(this.value);" /></td>
    <td rowspan="2"><input type="submit" value="Ââîä" style="width: 50px; height: 50px; font-weight: bold;" /></td>
   </tr>
   <tr>
    <td colspan="2"><input type="button" value="0" style="width: 62px;" onClick="s_write(this.value);" /></td>
    <td><input type="button" class="i_button" value="." onClick="s_write(this.value);" /></td>
    <td></td>
   </tr>
  </table>
 </form>
</body>
</html>

Автор: Alx 19.12.2004, 02:00
ну тогда и мой пример посмотрите! smile это был мой самый первый в жизни скрипт! smile
http://portfolio.alx.com.ru/scripts/javascript/sumball2.html

Автор: Наставник 19.12.2004, 04:03
Цитата(EXTR @ 19.12.2004, 01:55)
Исходник на JS, может понадобится.

Не это не дело на ЖаваСкрипт писать, так как встроенная функция eval - сама разбирает и вычисляет выражение, разговор же идет о том как лучше САМОМУ написать программу-скрипт - синтаксический анализатор.


Цитата(ALEXANDRO @ 19.12.2004, 02:00)
ну тогда и мой пример посмотрите!  это был мой самый первый в жизни скрипт!

Да и ваш пример, тоже :--(((

Смысл, в чем -- как это функция - eval работает, вот тут интересно, а так, тут и думать почти не надо.

Автор: Vinipoo 15.3.2006, 16:57
Пришлите программу РНР калькулятор, кто нибудь, сложный калькулятор.

Автор: Guedda 15.3.2006, 17:53
Что сложного? Конкретизируйте, пожалуйста...

Автор: CyClon 15.3.2006, 22:33
Хм, хочу написать калькулятор на PHP. Вот токо нада кнопки как-то заделать ан JS. У нас просто на информатике, в школе, все VB долбят, а я в блокноте пишу smile

Автор: Ciber SLasH 15.3.2006, 23:49
Имхо нерационально делать калькулятор на PHP, разве тока для баловства. Если и делать, то только на JS.

Автор: B2_Russia 19.9.2007, 23:47
Цитата(Ciber SLasH @ 15.3.2006,  23:49)
Имхо нерационально делать калькулятор на PHP, разве тока для баловства. Если и делать, то только на JS.

Сорри что тему поднял, но всеже...

Столкнулся с такой проблемой.
Нужно написать калькулятор, именно на PHP!
И нерациональность тут не при чем, я пишу калькулятор автострахования пользователь вводит не математическую формулу, а параметры такие как возраст, стаж вождения, марку авто, стоимость авто, и т.д. Система по этим параметрам заполняет некий набор переменных значениями. Эти переменные используются функцией при вычислении результата.
Система должна позволять менять формулу расчета.
Клиент, вводит данные и должен получить только результат расчета.

Так вот задача вполне востребованная, если ктото встречал решения, был бы премного благодарен ознакомиться с ним.

Возможно ктото знает как использовать http://ru.wikipedia.org/wiki/%D0%92%D0%B8%D0%BA%D0%B8%D0%BF%D0%B5%D0%B4%D0%B8%D1%8F:%D0%A4%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%B8_%D0%BF%D0%B0%D1%80%D1%81%D0%B5%D1%80%D0%B0

Вобщем, если кому интересно, давайте добьем тему, возможно она пригодится не один еще раз.

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

Автор: B2_Russia 21.9.2007, 00:36
Вобщем сделал, сами формулы считаю через eval с деревьями и пр. париться не стал =) 
Сделал возможность многострочной формулы со временными переменными (складываю в стек), плюс обрабатываются условные выражения
ЕСЛИ {cond} ТО {expr;expr;...} ИНАЧЕ {expr;expr;...}
Значения переменных подставляю через preg_replace();

Код

<?

class Formula
{
  var $db;
  var $VARS = array(); // массив переменных в котором содержится имена переменных и их значения
  // Массив "действий" а ля "T1=K2*K10/100*23.09" или "ЕСЛИ {T1>15} ТО {T2=21.8; T1=15} ИНАЧЕ {Т1=5}"
  // Функции должны быть записаны (упорядочены) по ходу вычислений!!!
  // Результат должен быть записан в переменную RESULT "RESULT = T1*T2/8.8"
  var $FUNCS = array(); 
  var $c_id;  // Идентификатор компании
  var $ot_id; // Тип ТС
  
  /////////////////////////////////////////////////////////////////////
  // Конструктор
  function Formula($VARS, $c_id, $ot_id)
  {
    global $g_db, $INFO;
    $this->db = & $g_db;
    $this->VARS = $VARS;
    $this->data = $data;
    $this->c_id = $c_id;
    $this->ot_id = $ot_id;
    
  // Функции должны быть записаны (упорядочены) по ходу вычислений!!!
    $this->db->query("SELECT fn_data FROM ".$INFO['sql_prefix']."functions WHERE fn_group_id='".$this->c_id."' ORDER BY fn_id");
    $this->FUNCS = $g_db->get_result();
  }
  /////////////////////////////////////////////////////////////////////
  // Добавляем в массив переменную
  function AddVariable($name, $value)
  {
    $index = sizeof($this->VARS);
    if (($this->VARS==NULL)||(!isset($this->VARS))) $index = 0;
    $this->VARS[$index]['name'] = $name;
    $this->VARS[$index]['value'] = $value;
  }
  
  function PostTemp($name, $value)
  {
    for ($i=0; $i<sizeof($this->VARS); $i++)
    {
      if ($this->VARS[$i]['name']==$name)
      {
        $this->VARS[$i]['value'] = $value;
        return;
      }
    }
    
    $newindex = sizeof($this->VARS);
    if (($this->VARS==NULL)||(!isset($this->VARS))) $newindex = 0;
    $this->VARS[$newindex]['name'] = $name;
    $this->VARS[$newindex]['value'] = $value;
    
  }
  
  function CheckCondition($data)
  {
    for ($i=0; $i<sizeof($this->VARS); $i++)
    {
      $reg = '/'.$this->VARS[$i]['name'].'([=*+\/\-]{0,1})/i';
      $to = $this->VARS[$i]['value'].'$1';
      
      $data = preg_replace($reg, $to, $data);
    }
    eval('$res='.$data.';');
    if ((!isset($res))||($res=='')) $res = 0;
    return $res;
  }
  
  function CalcExpression($data)
  {
    $src = $data;
    $res = null;
    for ($i=0; $i<sizeof($this->VARS); $i++)
    {
      $reg = '/'.$this->VARS[$i]['name'].'([=*+\/\-]{0,1})/i';
      $to = $this->VARS[$i]['value'].'$1';
      
      $data = preg_replace($reg, $to, $data);
    }
    eval('$res='.$data.';');
    return $res;
  }
  
  function CalcItem($data)
  {
      ////////////////////////////////////////////////////////////////////////////////
      // Смотрим какого типа выражение
      if (preg_match('/ЕСЛИ{(.*)}ТО{(.*)}ИНАЧЕ{(.*)}/', $data, $result))
      {
        //print_r($result);
        if ($this->CheckCondition($result[1]))
        {
          $exp = explode(';', $result[2]);
          for ($i=0; $i<sizeof($exp); $i++)
            $this->CalcItem($exp[$i]);
        }else
        {
          $exp = explode(';', $result[3]);
          for ($i=0; $i<sizeof($exp); $i++)
            $this->CalcItem($exp[$i]);
        }
          return false;
      }
      // Выражение = присваивание
      if (preg_match('/(.*)=(.*)/', $data, $result)>0)
      {
        $left = $result[1];
        $right = $result[2];
        $ResExpr = $this->CalcExpression($right);
        
        $this->PostTemp($left, $ResExpr);
      }
  }
  
  function Calc()
  {
    $RESULT = NULL;
    //print_r($this->VARS);
    for ($i=0; $i<sizeof($this->FUNCS); $i++)
    {
      $data = $this->FUNCS[$i]['fn_data'];
      // Удаляем все пробелы
      $data = preg_replace('/[ ]+/', '', $data);
      $this->CalcItem($data);
    }
  }
  
  function GetResult()
  {
    for ($i=0; $i<sizeof($this->VARS); $i++)
      if (strcmp($this->VARS[$i]['name'],'RESULT')==0) return $this->VARS[$i]['value'];
    return '-';
  }
} 

?>



Вобщем париться не стал абсолютно, все максимально для себя упростил (мне сейчас главное результат выкатить), если кто захочет обсудить - вэлком, я его несомненно буду оптимизировать/менять  и т.п., так что актуально.
Если кто что полезное посоветует буду рад!

Для наглядности скрин как это выглядит.


Автор: spectrre 22.4.2008, 15:50
Цитата(B2_Russia @ 21.9.2007,  00:36)
Вобщем сделал, сами формулы считаю через eval с деревьями и пр. париться не стал =) 
Сделал возможность многострочной формулы со временными переменными (складываю в стек), плюс обрабатываются условные выражения
ЕСЛИ {cond} ТО {expr;expr;...} ИНАЧЕ {expr;expr;...}
Значения переменных подставляю через preg_replace();

А можно еще небольшой пример использования данного класса разместить?? Очень заинтересовало, предстоит  почти аналогичная задачка...

Автор: awers 22.4.2008, 15:56
spectrre, может лучше о таком писать в ПМ, а не поднимать тему 2004 года

Автор: Feldmarschall 22.4.2008, 16:02
http://xbb.uz/calc/

Автор: CyClon 22.4.2008, 19:42
Как-то на олимпиаде по информатике попалась задачка, сделать парсер полинома:

Код
<?php

$data_in = file('poly.in');

$string = str_replace('x', rtrim($data_in[1]), rtrim($data_in[0]));
$string = preg_replace('~([0-9]+)\^([0-9]+)~e', 'pow("\\1", "\\2")', $string);
eval('$string = ' . $string . ';');

$data_out = fopen('poly.out', 'w');
fputs($data_out, $string . PHP_EOL);
fclose($data_out);

?>


Добавлено @ 19:43
Вообще сам калькулятор примерно так будет:

Код
<?php

$string = '55^23-45+33/22+66';

$string = preg_replace('~([0-9]+)\^([0-9]+)~e', 'pow("\\1", "\\2")', $string);
eval('$string = ' . $string . ';');

echo $string;

?>

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)