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; }
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; } }