public function getRandomValue()
 {
     //		@todo check this
     include_once "./Services/Math/classes/class.ilMath.php";
     $mul = ilMath::_pow(10, $this->getPrecision());
     $r1 = round(ilMath::_mul($this->getRangeMin(), $mul));
     $r2 = round(ilMath::_mul($this->getRangeMax(), $mul));
     $calcval = $this->getRangeMin() - 1;
     //test
     $roundedRangeMIN = round($this->getRangeMin(), $this->getPrecision());
     $roundedRangeMAX = round($this->getRangeMax(), $this->getPrecision());
     while ($calcval < $roundedRangeMIN || $calcval > $roundedRangeMAX) {
         $rnd = mt_rand($r1, $r2);
         $calcval = ilMath::_div($rnd, $mul, $this->getPrecision());
         if ($this->getPrecision() == 0 && $this->getIntprecision() != 0) {
             if ($this->getIntprecision() > 0) {
                 $modulo = $calcval % $this->getIntprecision();
                 if ($modulo != 0) {
                     if ($modulo < ilMath::_div($this->getIntprecision(), 2)) {
                         $calcval = ilMath::_sub($calcval, $modulo, $this->getPrecision());
                     } else {
                         $calcval = ilMath::_add($calcval, ilMath::_sub($this->getIntprecision(), $modulo, $this->getPrecision()), $this->getPrecision());
                     }
                 }
             }
         }
     }
     return $calcval;
 }
 /**
  * Returns the best solution for a given pass of a participant
  * @return array An associated array containing the best solution
  * @access public
  */
 public function getBestSolution($solutions)
 {
     $user_solution = array();
     foreach ($solutions as $idx => $solution_value) {
         if (preg_match("/^(\\\$v\\d+)\$/", $solution_value["value1"], $matches)) {
             $user_solution[$matches[1]] = $solution_value["value2"];
             $varObj = $this->getVariable($matches[1]);
             $varObj->setValue($solution_value["value2"]);
         } else {
             if (preg_match("/^(\\\$r\\d+)\$/", $solution_value["value1"], $matches)) {
                 if (!array_key_exists($matches[1], $user_solution)) {
                     $user_solution[$matches[1]] = array();
                 }
                 $user_solution[$matches[1]]["value"] = $solution_value["value2"];
             } else {
                 if (preg_match("/^(\\\$r\\d+)_unit\$/", $solution_value["value1"], $matches)) {
                     if (!array_key_exists($matches[1], $user_solution)) {
                         $user_solution[$matches[1]] = array();
                     }
                     $user_solution[$matches[1]]["unit"] = $solution_value["value2"];
                 }
             }
         }
     }
     foreach ($this->getResults() as $result) {
         $resVal = $result->calculateFormula($this->getVariables(), $this->getResults(), parent::getId(), false);
         if (is_object($result->getUnit())) {
             $user_solution[$result->getResult()]["unit"] = $result->getUnit()->getId();
             $user_solution[$result->getResult()]["value"] = $resVal;
         } else {
             if ($result->getUnit() == NULL) {
                 $unit_factor = 1;
                 // there is no fix result_unit, any "available unit" is accepted
                 $available_units = $result->getAvailableResultUnits(parent::getId());
                 $result_name = $result->getResult();
                 if ($available_units[$result_name] != NULL) {
                     $check_unit = in_array($user_solution[$result_name]['unit'], $available_units[$result_name]);
                 }
                 if ($check_unit == true) {
                     //get unit-factor
                     $unit_factor = assFormulaQuestionUnit::lookupUnitFactor($user_solution[$result_name]['unit']);
                     $user_solution[$result->getResult()]["value"] = round(ilMath::_div($resVal, $unit_factor), 55);
                 }
             }
         }
         if ($result->getResultType() == assFormulaQuestionResult::RESULT_CO_FRAC || $result->getResultType() == assFormulaQuestionResult::RESULT_FRAC) {
             $value = assFormulaQuestionResult::convertDecimalToCoprimeFraction($resVal);
             if (is_array($value)) {
                 $frac_helper = $value[1];
                 $value = $value[0];
             }
             $user_solution[$result->getResult()]["value"] = $value;
             $user_solution[$result->getResult()]["frac_helper"] = $frac_helper;
         } elseif ($result->getPrecision() > 0) {
             $user_solution[$result->getResult()]["value"] = round($resVal, $result->getPrecision());
         } else {
             $user_solution[$result->getResult()]["value"] = round($resVal);
         }
     }
     return $user_solution;
 }
Example #3
0
 function pfx($tokens, $vars = array())
 {
     if ($tokens == false) {
         return false;
     }
     $stack = new EvalMathStack();
     foreach ($tokens as $token) {
         // nice and easy
         // if the token is a binary operator, pop two values off the stack, do the operation, and push the result back on
         if (in_array($token, array('+', '-', '*', '/', '^'))) {
             if (is_null($op2 = $stack->pop())) {
                 return $this->trigger("internal error");
             }
             if (is_null($op1 = $stack->pop())) {
                 return $this->trigger("internal error");
             }
             include_once "class.ilMath.php";
             switch ($token) {
                 case '+':
                     $stack->push(ilMath::_add($op1, $op2));
                     break;
                 case '-':
                     $stack->push(ilMath::_sub($op1, $op2));
                     break;
                 case '*':
                     $stack->push(ilMath::_mul($op1, $op2));
                     break;
                 case '/':
                     if ($op2 == 0) {
                         return $this->trigger("division by zero");
                     }
                     $stack->push(ilMath::_div($op1, $op2));
                     break;
                 case '^':
                     $stack->push(ilMath::_pow($op1, $op2));
                     break;
             }
             // if the token is a unary operator, pop one value off the stack, do the operation, and push it back on
         } elseif ($token == "_") {
             $stack->push(-1 * $stack->pop());
             // if the token is a function, pop arguments off the stack, hand them to the function, and push the result back on
         } elseif (preg_match("/^([a-z]\\w*)\\(\$/", $token, $matches)) {
             // it's a function!
             $fnn = $matches[1];
             if (in_array($fnn, $this->fb)) {
                 // built-in function:
                 if (is_null($op1 = $stack->pop())) {
                     return $this->trigger("internal error");
                 }
                 $fnn = preg_replace("/^arc/", "a", $fnn);
                 // for the 'arc' trig synonyms
                 if ($fnn == 'ln') {
                     $fnn = 'log';
                 }
                 eval('$stack->push(' . $fnn . '($op1));');
                 // perfectly safe eval()
             } elseif (array_key_exists($fnn, $this->f)) {
                 // user function
                 // get args
                 $args = array();
                 for ($i = count($this->f[$fnn]['args']) - 1; $i >= 0; $i--) {
                     if (is_null($args[$this->f[$fnn]['args'][$i]] = $stack->pop())) {
                         return $this->trigger("internal error");
                     }
                 }
                 $stack->push($this->pfx($this->f[$fnn]['func'], $args));
                 // yay... recursion!!!!
             }
             // if the token is a number or variable, push it on the stack
         } else {
             if (is_numeric($token)) {
                 $stack->push($token);
             } elseif (($hex = $this->from_hexbin($token)) !== FALSE) {
                 $stack->push($hex);
             } elseif (array_key_exists($token, $this->v)) {
                 $stack->push($this->v[$token]);
             } elseif (array_key_exists($token, $vars)) {
                 $stack->push($vars[$token]);
             } else {
                 return $this->trigger("undefined variable '{$token}'");
             }
         }
     }
     // when we're out of tokens, the stack should have a single element, the final result
     if ($stack->count != 1) {
         return $this->trigger("internal error");
     }
     return $stack->pop();
 }
 public function getReachedPoints($variables, $results, $value, $unit, $units)
 {
     global $ilLog;
     if ($this->getRatingSimple()) {
         if ($this->isCorrect($variables, $results, $value, $units[$unit])) {
             return $this->getPoints();
         } else {
             return 0;
         }
     } else {
         $points = 0;
         include_once "./Services/Math/classes/class.EvalMath.php";
         include_once "./Services/Math/classes/class.ilMath.php";
         $formula = $this->substituteFormula($variables, $results);
         if (preg_match_all("/(\\\$v\\d+)/ims", $formula, $matches)) {
             foreach ($matches[1] as $variable) {
                 $varObj = $variables[$variable];
                 if (!is_object($varObj)) {
                     continue;
                 }
                 if ($varObj->getUnit() != NULL) {
                     //convert unit and value to baseunit
                     if ($varObj->getUnit()->getBaseUnit() != -1) {
                         $tmp_value = $varObj->getValue() * $varObj->getUnit()->getFactor();
                     } else {
                         $tmp_value = $varObj->getValue();
                     }
                 } else {
                     $tmp_value = $varObj->getValue();
                 }
                 $formula = preg_replace("/\\\$" . substr($variable, 1) . "(?![0-9]+)/", "(" . $tmp_value . ")" . "\\1", $formula);
             }
         }
         $math = new EvalMath();
         $math->suppress_errors = TRUE;
         $result = $math->evaluate($formula);
         // result_type extension
         switch ($this->getResultType()) {
             case assFormulaQuestionResult::RESULT_DEC:
                 if (substr_count($value, '.') == 1 || substr_count($value, ',') == 1) {
                     $exp_val = $value;
                     $frac_value = str_replace(',', '.', $exp_val);
                 } else {
                     $frac_value = $value;
                 }
                 $check_fraction = TRUE;
                 break;
             case assFormulaQuestionResult::RESULT_FRAC:
                 $exp_val = explode('/', $value);
                 if (count($exp_val) == 1) {
                     $frac_value = ilMath::_div($exp_val[0], 1, $this->getPrecision());
                     if (ilMath::_equals(abs($frac_value), abs($result), $this->getPrecision())) {
                         $check_fraction = TRUE;
                     } else {
                         $check_fraction = FALSE;
                     }
                 } else {
                     $frac_value = ilMath::_div($exp_val[0], $exp_val[1], $this->getPrecision());
                     if (ilMath::_equals(abs($frac_value), abs($result), $this->getPrecision())) {
                         $check_fraction = TRUE;
                     }
                 }
                 break;
             case assFormulaQuestionResult::RESULT_CO_FRAC:
                 $exp_val = explode('/', $value);
                 if (count($exp_val) == 1) {
                     $check_fraction = FALSE;
                 } else {
                     $frac_value = ilMath::_div($exp_val[0], $exp_val[1], $this->getPrecision());
                     if (self::isCoprimeFraction($exp_val[0], $exp_val[1])) {
                         $check_fraction = TRUE;
                     }
                 }
                 break;
             case assFormulaQuestionResult::RESULT_NO_SELECTION:
             default:
                 $check_fraction = TRUE;
                 break;
         }
         // result unit!!
         if (is_object($this->getUnit())) {
             // if expected resultunit != baseunit convert to resultunit
             if ($this->getUnit()->getBaseUnit() != -1) {
                 $result = ilMath::_div($result, $this->getUnit()->getFactor(), $this->getPrecision());
             } else {
                 //if resultunit == baseunit calculate to get correct precision
                 $result = ilMath::_mul($result, $this->getUnit()->getFactor(), $this->getPrecision());
             }
         }
         if (is_object($unit)) {
             if (isset($frac_value)) {
                 $value = ilMath::_mul($frac_value, $unit->getFactor(), 100);
             }
         }
         if ($this->checkSign($result, $value)) {
             $points += ilMath::_mul($this->getPoints(), ilMath::_div($this->getRatingSign(), 100));
         }
         if ($this->isInTolerance(abs($value), abs($result), $this->getTolerance())) {
             $points += ilMath::_mul($this->getPoints(), ilMath::_div($this->getRatingValue(), 100));
         }
         if (is_object($this->getUnit())) {
             $base1 = $units[$unit];
             if (is_object($base1)) {
                 $base1 = $units[$base1->getBaseUnit()];
             }
             $base2 = $units[$this->getUnit()->getBaseUnit()];
             if (is_object($base1) && is_object($base2) && $base1->getId() == $base2->getId()) {
                 $points += ilMath::_mul($this->getPoints(), ilMath::_div($this->getRatingUnit(), 100));
             }
         }
         return $points;
     }
 }
 public function getResultInfo($variables, $results, $value, $unit, $units)
 {
     if ($this->getRatingSimple()) {
         if ($this->isCorrect($variables, $results, $value, $units[$unit])) {
             return array("points" => $this->getPoints());
         } else {
             return array("points" => 0);
         }
     } else {
         include_once "./Services/Math/classes/class.EvalMath.php";
         include_once "./Services/Math/classes/class.ilMath.php";
         $totalpoints = 0;
         $formula = $this->substituteFormula($variables, $results);
         if (preg_match_all("/(\\\$v\\d+)/ims", $formula, $matches)) {
             foreach ($matches[1] as $variable) {
                 $varObj = $variables[$variable];
                 $formula = preg_replace("/\\\$" . substr($variable, 1) . "([^0123456789]{0,1})/", $varObj->getBaseValue() . "\\1", $formula);
             }
         }
         $math = new EvalMath();
         $math->suppress_errors = TRUE;
         $result = $math->evaluate($formula);
         if (is_object($this->getUnit())) {
             $result = ilMath::_mul($result, $this->getUnit()->getFactor(), 100);
         }
         if (is_object($unit)) {
             $value = ilMath::_mul($value, $unit->getFactor(), 100);
         } else {
         }
         $details = array();
         if ($this->checkSign($result, $value)) {
             $points = ilMath::_mul($this->getPoints(), ilMath::_div($this->getRatingSign(), 100));
             $totalpoints += $points;
             $details['sign'] = $points;
         }
         if ($this->isInTolerance(abs($value), abs($result), $this->getTolerance())) {
             $points = ilMath::_mul($this->getPoints(), ilMath::_div($this->getRatingValue(), 100));
             $totalpoints += $points;
             $details['value'] = $points;
         }
         if (is_object($this->getUnit())) {
             $base1 = $units[$unit];
             if (is_object($base1)) {
                 $base1 = $units[$base1->getBaseUnit()];
             }
             $base2 = $units[$this->getUnit()->getBaseUnit()];
             if (is_object($base1) && is_object($base2) && $base1->getId() == $base2->getId()) {
                 $points = ilMath::_mul($this->getPoints(), ilMath::_div($this->getRatingUnit(), 100));
                 $totalpoints += $points;
                 $details['unit'] = $points;
             }
         }
         $details['points'] = $totalpoints;
         return $details;
     }
 }