43         private string $result,
    44         private ?
string $range_min_txt,
    45         private ?
string $range_max_txt,
    46         private float $tolerance,
    48         private ?
string $formula,
    49         private float $points,
    50         private int $precision,
    51         private bool $rating_simple = 
true,
    52         private ?
float $rating_sign = null,
    53         private ?
float $rating_value = null,
    54         private ?
float $rating_unit = null,
    55         private float $result_type = 0
    58         $this->main_tpl = $DIC->ui()->mainTemplate();
    60         $this->
lng = $DIC->language();
    64         if ($rating_sign === null) {
    65             $this->rating_sign = 33;
    67         if ($rating_value === null) {
    68             $this->rating_value = 34;
    70         if ($rating_unit === null) {
    71             $this->rating_unit = 33;
    78         preg_match_all(
'/\$r\d+/mi', $formula, $matches);
    80         foreach ($matches[0] as $result) {
    82                 $this->main_tpl->setOnScreenMessage(
'failure', $this->
lng->txt(
'errRecursionInResult'));
    86             if (!isset($results[$result]) || !$results[$result] instanceof 
self) {
    87                 $this->main_tpl->setOnScreenMessage(
'failure', $this->
lng->txt(
'errFormulaQuestion'));
    91             $formula = preg_replace(
    92                 '/\\' . $result . 
'(?!\d)/m',
    98         return "({$formula})";
   103         $resultunits = array();
   104         if ($question_id > 0) {
   109         if (preg_match_all(
"/(\\\$v\\d+)/ims", $formula, $matches)) {
   110             foreach ($matches[1] as $variable) {
   111                 $varObj = $variables[$variable];
   112                 if (!is_object($varObj) || !is_numeric($varObj->getValue())) {
   115                 $value = $varObj->getBaseValue();
   116                 $formula = preg_replace(
"/\\\$" . substr($variable, 1) . 
"(?![0-9]+)/", 
"(" . $value . 
")" . 
"\\1", $formula);
   120         $math->suppress_errors = 
true;
   122         $formula = str_replace(
",", 
".", $formula);
   123         $result = $math->evaluate($formula);
   124         if ($this->
getUnit() !== null) {
   130         if ($use_precision == 
true) {
   145         while ($i < 1000 && !$inRange) {
   147             if (preg_match_all(
"/(\\\$v\\d+)/ims", $formula, $matches)) {
   148                 foreach ($matches[1] as $variable) {
   149                     $varObj = $variables[$variable];
   150                     if (!is_object($varObj)) {
   153                     $varObj->setRandomValue();
   154                     $formula = preg_replace(
"/\\\$" . substr($variable, 1) . 
"(?![0-9]+)/", 
"(" . $varObj->getBaseValue() . 
")" . 
"\\1", $formula);
   158             $math->suppress_errors = 
true;
   159             $result = $math->evaluate($formula);
   160             $inRange = (is_numeric($result)) ? 
true : 
false;
   182         for ($i = 0; $i < 1000; $i++) {
   184             if (preg_match_all(
"/(\\\$v\\d+)/ims", $formula, $matches)) {
   185                 foreach ($matches[1] as $variable) {
   186                     $varObj = $variables[$variable];
   187                     if (!is_object($varObj)) {
   190                     $varObj->setRandomValue();
   191                     $formula = preg_replace(
"/\\\$" . substr($variable, 1) . 
"(?![0-9]+)/", 
"(" . $varObj->getBaseValue() . 
")" . 
"\\1", $formula);
   195             $math->suppress_errors = 
true;
   196             $result = $math->evaluate($formula);
   197             if (($range_min == null) || ($result < $range_min)) {
   198                 $range_min = $result;
   200             if (($range_max == null) || ($result > $range_max)) {
   201                 $range_max = $result;
   204         if ($this->
getUnit() !== null) {
   222         if ($value === null || 0 == strlen($value)) {
   225         $value = str_replace(
' ', 
'', $value);
   229         $check_valid_chars = 
true;
   231         if (preg_match_all(
"/(\\\$v\\d+)/ims", $formula, $matches)) {
   232             foreach ($matches[1] as $variable) {
   233                 $varObj = $variables[$variable];
   234                 if (!is_object($varObj) || !is_numeric($varObj->getValue())) {
   238                 if ($varObj->getUnit() != null) {
   240                     if ($varObj->getUnit()->getBaseUnit() != -1) {
   241                         $tmp_value = $varObj->getValue() * $varObj->getUnit()->getFactor();
   243                         $tmp_value = $varObj->getValue();
   246                     $tmp_value = $varObj->getValue();
   249                 $formula = preg_replace(
"/\\\$" . substr($variable, 1) . 
"(?![0-9]+)/", 
"(" . $tmp_value . 
")" . 
"\\1", $formula);
   254         $math->suppress_errors = 
true;
   255         $result = $math->evaluate($formula); 
   256         $resultWithRespectedUnit = $result;
   258         if ($this->
getUnit() !== null) {
   262             if ($this->
getUnit()->getBaseUnit() != -1) {
   265         } elseif ($this->
getUnit() == null && $unit != null) {
   269             if ($unit->getFactor() != 1 && strlen(trim($unit->getFactor())) != 1) {
   271                 $resultWithRespectedUnit = 
ilMath::_div($result, $unit->getFactor());
   275         $result = substr($result, 0, strlen($resultWithRespectedUnit));
   278         $has_valid_chars = preg_match(
"/^-?([0-9]*)(,|\\.|\\/){0,1}([0-9]*)([eE][\\+|-]([0-9])+)?$/", $value, $matches);
   279         if (!$has_valid_chars) {
   280             $check_valid_chars = 
false;
   282             (isset($matches[2]) && $matches[2] == 
'/') &&
   283             (isset($matches[4]) && strtolower($matches[4]) == 
"e") &&
   284             (!isset($matches[1]) || !strlen($matches[1]) || !isset($matches[3]) || !strlen($matches[3]) || $matches[3] == 0)) {
   285             $check_valid_chars = 
false;
   291                 if (substr_count($value, 
'.') == 1 || substr_count($value, 
',') == 1) {
   293                     $frac_value = str_replace(
',', 
'.', $exp_val);
   295                     $frac_value = $value;
   298                 if (substr_count($value, 
'/') >= 1) {
   299                     $check_fraction = 
false;
   301                     $check_fraction = 
true;
   307                 $exp_val = explode(
'/', $value);
   308                 if (count($exp_val) == 1) {
   311                     if (ilMath::_equals($frac_value, $resultWithRespectedUnit, $this->
getPrecision())) {
   312                         $check_fraction = 
true;
   314                         $check_fraction = 
false;
   326                     $frac_value = str_replace(
',', 
'.', $frac_value);
   328                     if (ilMath::_equals($frac_value, $resultWithRespectedUnit, $this->
getPrecision())) {
   329                         $check_fraction = 
true;
   333                         if (!self::isCoprimeFraction($exp_val[0], $exp_val[1])) {
   334                             $check_fraction = 
false;
   339                 if (substr_count($value, 
'.') >= 1 || substr_count($value, 
',') >= 1) {
   340                     $check_fraction = 
false;
   346                 if (substr_count($value, 
'.') == 1 || substr_count($value, 
',') == 1) {
   347                     $frac_value = str_replace(
',', 
'.', $value);
   348                 } elseif (substr_count($value, 
'/') == 1) {
   349                     $exp_val = explode(
'/', $value);
   360                     $frac_value = $value;
   363                 $check_fraction = 
true;
   367         if (is_object($unit)) {
   368             if (isset($frac_value)) {
   369                 $value = 
ilMath::_mul($frac_value, $unit->getFactor(), 100);
   373         $frac_value = ilMath::_round($frac_value, $this->
getPrecision());
   374         $resultWithRespectedUnit = ilMath::_round($resultWithRespectedUnit, $this->
getPrecision());
   377         if (isset($frac_value)) {
   388         if ($this->
getUnit() !== null) {
   389             if (is_object($unit)) {
   390                 if ($unit->getId() != $this->
getUnit()->getId()) {
   395         return $checkvalue && $checkunit && $check_fraction && $check_valid_chars;
   398     protected function isInTolerance($user_answer, $expected, $tolerated_percentage): bool
   402         $lower_boundary = 
ilMath::_sub($expected, $tolerance_abs);
   403         $upper_boundary = 
ilMath::_add($expected, $tolerance_abs);
   405         return $lower_boundary <= $user_answer
   406             && $user_answer <= $upper_boundary;
   411         return ($v1 >= 0.0 && $v2 >= 0.0) || ($v1 <= 0.0 && $v2 <= 0.0);
   420         string $answer_value,
   425             return $this->
isCorrect($variables, $results, $answer_value, $answer_unit)
   435             $base1 = $units[$answer_unit->
getBaseUnit()] ?? null;
   436             $base2 = $units[$answer_unit->
getBaseUnit()] ?? null;
   438                 $base1 instanceof assFormulaQuestionUnit
   439                 && $base2 instanceof assFormulaQuestionUnit
   440                 && $base1->getId() === $base2->getId()
   446         if ($float_value === null) {
   450         if ($this->
checkSign($result, $float_value)) {
   474             case self::RESULT_DEC:
   476             case self::RESULT_FRAC:
   477             case self::RESULT_CO_FRAC:
   478                 $exp_val = explode(
'/', $value);
   481                     count($exp_val) === 1 ? 1 : $exp_val[1],
   485             case self::RESULT_NO_SELECTION:
   487                 $exp_val = explode(
'/', $value);
   489                 if (count($exp_val) === 2
   490                     && (
float) $exp_val[1] === 0.0) {
   496                     count($exp_val) === 1 ? 1 : $exp_val[1],
   502             $this->
refinery->kindlyTo()->float(),
   504         ])->transform(round($value, $this->precision));
   511                 return array(
"points" => $this->
getPoints());
   513                 return array(
"points" => 0);
   518             if (preg_match_all(
"/(\\\$v\\d+)/ims", $formula, $matches)) {
   519                 foreach ($matches[1] as $variable) {
   520                     $varObj = $variables[$variable];
   521                     $formula = preg_replace(
"/\\\$" . substr($variable, 1) . 
"(?![0-9]+)/", 
"(" . $varObj->getBaseValue() . 
")" . 
"\\1", $formula);
   525             $math->suppress_errors = 
true;
   526             $result = $math->evaluate($formula);
   527             if ($this->
getUnit() !== null) {
   530             if (is_object($unit)) {
   537                 $totalpoints += $points;
   542                 $totalpoints += $points;
   545             if ($this->
getUnit() !== null) {
   546                 $base1 = $units[$unit];
   547                 if (is_object($base1)) {
   548                     $base1 = $units[$base1->getBaseUnit()];
   550                 $base2 = $units[$this->
getUnit()->getBaseUnit()];
   551                 if (is_object($base1) && is_object($base2) && $base1->getId() == $base2->getId()) {
   553                     $totalpoints += $points;
   568         $this->result = $result;
   573         return $this->result;
   578         if ($range_min === null) {
   583         $math->suppress_errors = 
true;
   584         $this->range_min = (float) $math->evaluate($range_min);
   594         if ($this->
getUnit() !== null) {
   603         if ($range_max === null) {
   608         $math->suppress_errors = 
true;
   609         $this->range_max = (float) $math->evaluate($range_max);
   619         if ($this->
getUnit() !== null) {
   628         $this->tolerance = $tolerance;
   633         return $this->tolerance;
   648         $this->formula = $formula;
   653         return $this->formula;
   658         $this->points = $points;
   663         return $this->points;
   668         $this->rating_simple = $rating_simple;
   673         return $this->rating_simple;
   678         $this->rating_sign = $rating_sign;
   683         return $this->rating_sign;
   688         $this->rating_value = $rating_value;
   693         return $this->rating_value;
   698         $this->rating_unit = $rating_unit;
   703         return $this->rating_unit;
   708         $this->precision = $precision;
   713         return $this->precision;
   718         $this->result_type = $a_result_type;
   723         return (
int) $this->result_type;
   728         $this->range_max_txt = $range_max_txt;
   733         return $this->range_max_txt;
   738         $this->range_min_txt = $range_min_txt;
   743         return $this->range_min_txt;
   749         $ilDB = $DIC[
'ilDB'];
   754                         FROM il_qpl_qst_fq_res   755                         WHERE question_fi = %s   757             array(
'integer', 
'text'),
   758             array($a_qst_id, $a_result)
   763         return $row[
'result_type'];
   768         $gcd = self::getGreatestCommonDivisor(abs($numerator), abs($denominator));
   770         return $gcd == 1 ? true : 
false;
   775         if (empty($decimal_value)) {
   779         $to_string = (string) $decimal_value;
   780         $is_negative = strpos($to_string, 
'-') === 0;
   782             $decimal_value = substr($decimal_value, 1);
   788         $b = 1 / $decimal_value;
   793             $h1 = 
$a * $h1 + $h2;
   796             $k1 = 
$a * $k1 + $k2;
   799         } 
while ((abs($decimal_value - $h1 / $k1) > $decimal_value * $tolerance) || ($k1 < 0 || 
$b < 0));
   805             $checkResult = ($h1 / $k1);
   808             $result = 
'-' . $result;
   809             $checkResult = ($h1 / $k1) * -1;
   811         if ($to_string == $checkResult . 
'' || $checkResult . 
'' == $result) {
   814             return array($to_string,$result);
   821             return self::getGreatestCommonDivisor(
$b, 
$a % 
$b);
   831         $ilDB = $DIC[
'ilDB'];
   835                         SELECT * FROM il_qpl_qst_fq_res_unit   836                         WHERE question_fi = %s   844             $this->available_units[$row[
'result']][] = $row[
'unit_fi'] ;
 
static _add($left_operand, $right_operand, int $scale=50)
 
static _div($left_operand, $right_operand, int $scale=50)
 
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
 
static _sub($left_operand, $right_operand, int $scale=50)
 
$a
thx to https://mlocati.github.io/php-cs-fixer-configurator for the examples 
 
static _mul($left_operand, $right_operand, int $scale=50)