ILIAS  trunk Revision v11.0_alpha-2638-g80c1d007f79
class.assFormulaQuestionResult.php
Go to the documentation of this file.
1 <?php
2 
20 
28 {
29  public const RESULT_NO_SELECTION = 0;
30  public const RESULT_DEC = 1;
31  public const RESULT_FRAC = 2;
32  public const RESULT_CO_FRAC = 3;
33 
36  private ilLanguage $lng;
37 
38  private $available_units = [];
39  private ?float $range_min = null;
40  private ?float $range_max = null;
41 
42  public function __construct(
43  private string $result,
44  private ?string $range_min_txt,
45  private ?string $range_max_txt,
46  private float $tolerance,
47  private ?assFormulaQuestionUnit $unit,
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
56  ) {
57  global $DIC;
58  $this->main_tpl = $DIC->ui()->mainTemplate();
59  $this->refinery = $DIC->refinery();
60  $this->lng = $DIC->language();
61  $this->setRangeMin($range_min_txt);
62  $this->setRangeMax($range_max_txt);
63 
64  if ($rating_sign === null) {
65  $this->rating_sign = 33;
66  }
67  if ($rating_value === null) {
68  $this->rating_value = 34;
69  }
70  if ($rating_unit === null) {
71  $this->rating_unit = 33;
72  }
73  }
74 
75  public function substituteFormula(array $variables, array $results): false|string
76  {
77  $formula = $this->getFormula();
78  preg_match_all('/\$r\d+/mi', $formula, $matches);
79 
80  foreach ($matches[0] as $result) {
81  if ($result === $this->getResult()) {
82  $this->main_tpl->setOnScreenMessage('failure', $this->lng->txt('errRecursionInResult'));
83  return false;
84  }
85 
86  if (!isset($results[$result]) || !$results[$result] instanceof self) {
87  $this->main_tpl->setOnScreenMessage('failure', $this->lng->txt('errFormulaQuestion'));
88  return false;
89  }
90 
91  $formula = preg_replace(
92  '/\\' . $result . '(?!\d)/m',
93  $results[$result]->substituteFormula($variables, $results),
94  $formula,
95  );
96  }
97 
98  return "({$formula})";
99  }
100 
101  public function calculateFormula($variables, $results, $question_id = 0, $use_precision = true)
102  {
103  $resultunits = [];
104  if ($question_id > 0) {
105  $resultunits = $this->getAvailableResultUnits($question_id);
106  }
107 
108  $formula = $this->substituteFormula($variables, $results);
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())) {
113  continue;
114  }
115  $value = $varObj->getBaseValue();
116  $formula = preg_replace("/\\\$" . substr($variable, 1) . "(?![0-9]+)/", "(" . $value . ")" . "\\1", $formula);
117  }
118  }
119  $math = new EvalMath();
120  $math->suppress_errors = true;
121 
122  $formula = str_replace(",", ".", $formula);
123  $result = $math->evaluate($formula);
124  if ($this->getUnit() !== null) {
125  $result = ilMath::_div($result, $this->getUnit()->getFactor(), 100);
126  }
127 
128  // @todo DON'T USE ilMath::_mul() ... bcmul() returns wrong result !!!!
129 
130  if ($use_precision == true) {
131  $res = $result * 1;
132  if (is_numeric($this->getPrecision())) {
133  if ($this->getResultType() == self::RESULT_DEC || $this->getResultType() == self::RESULT_NO_SELECTION) {
134  $result = ilMath::_round($res, $this->getPrecision());
135  }
136  }
137  }
138  return $result;
139  }
140 
141  public function findValidRandomVariables($variables, $results): void
142  {
143  $i = 0;
144  $inRange = false;
145  while ($i < 1000 && !$inRange) {
146  $formula = $this->substituteFormula($variables, $results);
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)) {
151  continue;
152  }
153  $varObj->setRandomValue();
154  $formula = preg_replace("/\\\$" . substr($variable, 1) . "(?![0-9]+)/", "(" . $varObj->getBaseValue() . ")" . "\\1", $formula);
155  }
156  }
157  $math = new EvalMath();
158  $math->suppress_errors = true;
159  $result = $math->evaluate($formula);
160  $inRange = (is_numeric($result)) ? true : false;
161  if ($inRange) {
162  if (is_numeric($this->getRangeMin())) {
163  if ($result < $this->getRangeMinBase()) {
164  $inRange = false;
165  }
166  }
167  if (is_numeric($this->getRangeMax())) {
168  if ($result > $this->getRangeMaxBase()) {
169  $inRange = false;
170  }
171  }
172  }
173  $i++;
174  }
175  }
176 
177  public function suggestRange($variables, $results): void
178  {
179  // @todo Check this
180  $range_min = null;
181  $range_max = null;
182  for ($i = 0; $i < 1000; $i++) {
183  $formula = $this->substituteFormula($variables, $results);
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)) {
188  continue;
189  }
190  $varObj->setRandomValue();
191  $formula = preg_replace("/\\\$" . substr($variable, 1) . "(?![0-9]+)/", "(" . $varObj->getBaseValue() . ")" . "\\1", $formula);
192  }
193  }
194  $math = new EvalMath();
195  $math->suppress_errors = true;
196  $result = $math->evaluate($formula);
197  if (($range_min == null) || ($result < $range_min)) {
198  $range_min = $result;
199  }
200  if (($range_max == null) || ($result > $range_max)) {
201  $range_max = $result;
202  }
203  }
204  if ($this->getUnit() !== null) {
205  $range_min = ilMath::_div($range_min, $this->getUnit()->getFactor());
206  $range_max = ilMath::_div($range_max, $this->getUnit()->getFactor());
207  }
208  $this->setRangeMin(ilMath::_mul($range_min, 1, $this->getPrecision()));
209  $this->setRangeMax(ilMath::_mul($range_max, 1, $this->getPrecision()));
210  }
211 
219  public function isCorrect($variables, $results, $value, $unit = null): bool
220  {
221  // The user did not answer the question ....
222  if ($value === null || 0 == strlen($value)) {
223  return false;
224  }
225  $value = str_replace(' ', '', $value);
226 
227  $formula = $this->substituteFormula($variables, $results);
228 
229  $check_valid_chars = true;
230 
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())) {
235  continue;
236  }
237 
238  if ($varObj->getUnit() != null) {
239  //convert unit and value to baseunit.... because vars could have different units
240  if ($varObj->getUnit()->getBaseUnit() != -1) {
241  $tmp_value = $varObj->getValue() * $varObj->getUnit()->getFactor();
242  } else {
243  $tmp_value = $varObj->getValue();
244  }
245  } else {
246  $tmp_value = $varObj->getValue();
247  }
248 
249  $formula = preg_replace("/\\\$" . substr($variable, 1) . "(?![0-9]+)/", "(" . $tmp_value . ")" . "\\1", $formula);
250  }
251  }
252 
253  $math = new EvalMath();
254  $math->suppress_errors = true;
255  $result = $math->evaluate($formula); // baseunit-result!!
256  $resultWithRespectedUnit = $result;
257 
258  if ($this->getUnit() !== null) {
259  //there is a "fix" result_unit defined!
260 
261  // if expected resultunit != baseunit convert to "fix" result_unit
262  if ($this->getUnit()->getBaseUnit() != -1) {
263  $resultWithRespectedUnit = ilMath::_div($result, $this->getUnit()->getFactor());
264  }
265  } elseif ($this->getUnit() == null && $unit != null) {
266  // there is no "fix" result_unit defined, but the user has selected a unit ...
267  // so .... there are "available resultunits" in multi-selectbox selected
268  // -> check if selected user-unit is baseunit
269  if ($unit->getFactor() != 1 && strlen(trim($unit->getFactor())) != 1) {
270  // result is already calculated to baseunit.... -> get correct precision..
271  $resultWithRespectedUnit = ilMath::_div($result, $unit->getFactor());
272  }
273  }
274 
275  $result = substr($result, 0, strlen($resultWithRespectedUnit));
276 
277  // check for valid chars ("0-9",",|.|/","0-9","e|E","+|-","0-9")
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;
281  } elseif (
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;
286  }
287 
288  // result_type extension
289  switch ($this->getResultType()) {
291  if (substr_count($value, '.') == 1 || substr_count($value, ',') == 1) {
292  $exp_val = $value;
293  $frac_value = str_replace(',', '.', $exp_val);
294  } else {
295  $frac_value = $value;
296  }
297 
298  if (substr_count($value, '/') >= 1) {
299  $check_fraction = false;
300  } else {
301  $check_fraction = true;
302  }
303  break;
304 
307  $exp_val = explode('/', $value);
308  if (count($exp_val) == 1) {
309  $frac_value = ilMath::_div($exp_val[0], 1);
310 
311  if (ilMath::_equals($frac_value, $resultWithRespectedUnit, $this->getPrecision())) {
312  $check_fraction = true;
313  } else {
314  $check_fraction = false;
315  }
316  } else {
317  try {
318  $frac_value = ilMath::_div($exp_val[0], $exp_val[1]);
319  } catch (ilMathDivisionByZeroException $ex) {
320  if ($result) {
321  return false;
322  } else {
323  return true;
324  }
325  }
326  $frac_value = str_replace(',', '.', $frac_value);
327 
328  if (ilMath::_equals($frac_value, $resultWithRespectedUnit, $this->getPrecision())) {
329  $check_fraction = true;
330  }
331 
333  if (!self::isCoprimeFraction($exp_val[0], $exp_val[1])) {
334  $check_fraction = false;
335  }
336  }
337  }
338 
339  if (substr_count($value, '.') >= 1 || substr_count($value, ',') >= 1) {
340  $check_fraction = false;
341  }
342  break;
343 
345  default:
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);
350  try {
351  $frac_value = ilMath::_div($exp_val[0], $exp_val[1]);
352  } catch (ilMathDivisionByZeroException $ex) {
353  if ($result) {
354  return false;
355  } else {
356  return true;
357  }
358  }
359  } else {
360  $frac_value = $value;
361  }
362 
363  $check_fraction = true;
364  break;
365  }
366 
367  if (is_object($unit)) {
368  if (isset($frac_value)) {
369  $value = ilMath::_mul($frac_value, $unit->getFactor(), 100);
370  }
371  }
372 
373  $frac_value = ilMath::_round($frac_value, $this->getPrecision());
374  $resultWithRespectedUnit = ilMath::_round($resultWithRespectedUnit, $this->getPrecision());
375 
376  $checkvalue = false;
377  if (isset($frac_value)) {
378  if ($this->isInTolerance($frac_value, $resultWithRespectedUnit, $this->getTolerance())) {
379  $checkvalue = true;
380  }
381  } else {
382  if ($this->isInTolerance($value, $resultWithRespectedUnit, $this->getTolerance())) {
383  $checkvalue = true;
384  }
385  }
386 
387  $checkunit = true;
388  if ($this->getUnit() !== null) {
389  if (is_object($unit)) {
390  if ($unit->getId() != $this->getUnit()->getId()) {
391  $checkunit = false;
392  }
393  }
394  }
395  return $checkvalue && $checkunit && $check_fraction && $check_valid_chars;
396  }
397 
398  protected function isInTolerance($user_answer, $expected, $tolerated_percentage): bool
399  {
400  $user_answer = ilMath::_mul($user_answer, 1, $this->getPrecision());
401  $tolerance_abs = abs(ilMath::_div(ilMath::_mul($tolerated_percentage, $expected, 100), 100));
402  $lower_boundary = ilMath::_sub($expected, $tolerance_abs);
403  $upper_boundary = ilMath::_add($expected, $tolerance_abs);
404 
405  return $lower_boundary <= $user_answer
406  && $user_answer <= $upper_boundary;
407  }
408 
409  private function checkSign(float $v1, float $v2): bool
410  {
411  return ($v1 >= 0.0 && $v2 >= 0.0) || ($v1 <= 0.0 && $v2 <= 0.0);
412  }
413 
417  public function getReachedPoints(
418  array $variables,
419  array $results,
420  string $answer_value,
421  ?assFormulaQuestionUnit $answer_unit,
422  array $units
423  ): float {
424  if ($this->getRatingSimple()) {
425  return $this->isCorrect($variables, $results, $answer_value, $answer_unit)
426  ? $this->getPoints()
427  : 0.0;
428  }
429 
430  $result = $this->calculateCorrectResult($variables, $results);
431  $float_value = $this->transformAnswerValueAccordingToType($answer_value, $answer_unit);
432 
433  $points = 0.0;
434  if ($answer_unit instanceof assFormulaQuestionUnit && $answer_unit instanceof assFormulaQuestionUnit) {
435  $base1 = $units[$answer_unit->getBaseUnit()] ?? null;
436  $base2 = $units[$answer_unit->getBaseUnit()] ?? null;
437  if (
438  $base1 instanceof assFormulaQuestionUnit
439  && $base2 instanceof assFormulaQuestionUnit
440  && $base1->getId() === $base2->getId()
441  ) {
442  $points += ilMath::_mul($this->getPoints(), ilMath::_div($this->getRatingUnit(), 100));
443  }
444  }
445 
446  if ($float_value === null) {
447  return $points;
448  }
449 
450  if ($this->checkSign($result, $float_value)) {
451  $points += ilMath::_mul($this->getPoints(), ilMath::_div($this->getRatingSign(), 100));
452  }
453 
454  if ($this->isInTolerance(abs($float_value), abs($result), $this->getTolerance())) {
455  $points += ilMath::_mul($this->getPoints(), ilMath::_div($this->getRatingValue(), 100));
456  }
457 
458  return $points;
459  }
460 
461  private function calculateCorrectResult(array $variables, array $results): float
462  {
463  return round(
464  $this->calculateFormula($variables, $results),
465  $this->precision
466  );
467  }
468 
470  string $value,
472  ): ?float {
473  switch ($this->getResultType()) {
474  case self::RESULT_DEC:
475  break;
476  case self::RESULT_FRAC:
477  case self::RESULT_CO_FRAC:
478  $exp_val = explode('/', $value);
479  $value = ilMath::_div(
480  $exp_val[0],
481  count($exp_val) === 1 ? 1 : $exp_val[1],
482  $this->getPrecision()
483  );
484  break;
485  case self::RESULT_NO_SELECTION:
486  default:
487  $exp_val = explode('/', $value);
488 
489  if (count($exp_val) === 2
490  && (float) $exp_val[1] === 0.0) {
491  return null;
492  }
493 
494  $value = ilMath::_div(
495  $exp_val[0],
496  count($exp_val) === 1 ? 1 : $exp_val[1],
497  100
498  );
499  }
500 
501  return $this->refinery->byTrying([
502  $this->refinery->kindlyTo()->float(),
503  $this->refinery->always(null),
504  ])->transform(round($value, $this->precision));
505  }
506 
507  public function getResultInfo($variables, $results, $value, $unit, $units): array
508  {
509  if ($this->getRatingSimple()) {
510  if ($this->isCorrect($variables, $results, $value, $units[$unit] ?? null)) {
511  return ["points" => $this->getPoints()];
512  } else {
513  return ["points" => 0];
514  }
515  } else {
516  $totalpoints = 0;
517  $formula = $this->substituteFormula($variables, $results);
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);
522  }
523  }
524  $math = new EvalMath();
525  $math->suppress_errors = true;
526  $result = $math->evaluate($formula);
527  if ($this->getUnit() !== null) {
528  $result = ilMath::_mul($result, $this->getUnit()->getFactor(), 100);
529  }
530  if (is_object($unit)) {
531  $value = ilMath::_mul($value, $unit->getFactor(), 100);
532  } else {
533  }
534  $details = [];
535  if ($this->checkSign($result, $value)) {
536  $points = ilMath::_mul($this->getPoints(), $this->getRatingSign() / 100);
537  $totalpoints += $points;
538  $details['sign'] = $points;
539  }
540  if ($this->isInTolerance(abs($value), abs($result), $this->getTolerance())) {
541  $points = ilMath::_mul($this->getPoints(), $this->getRatingValue() / 100);
542  $totalpoints += $points;
543  $details['value'] = $points;
544  }
545  if ($this->getUnit() !== null) {
546  $base1 = $units[$unit];
547  if (is_object($base1)) {
548  $base1 = $units[$base1->getBaseUnit()];
549  }
550  $base2 = $units[$this->getUnit()->getBaseUnit()];
551  if (is_object($base1) && is_object($base2) && $base1->getId() == $base2->getId()) {
552  $points = ilMath::_mul($this->getPoints(), $this->getRatingUnit() / 100);
553  $totalpoints += $points;
554  $details['unit'] = $points;
555  }
556  }
557  $details['points'] = $totalpoints;
558  return $details;
559  }
560  }
561 
562  /************************************
563  * Getter and Setter
564  ************************************/
565 
566  public function setResult($result): void
567  {
568  $this->result = $result;
569  }
570 
571  public function getResult(): string
572  {
573  return $this->result;
574  }
575 
576  public function setRangeMin(?string $range_min): void
577  {
578  if ($range_min === null) {
579  return;
580  }
581 
582  $math = new EvalMath();
583  $math->suppress_errors = true;
584  $this->range_min = (float) $math->evaluate($range_min);
585  }
586 
587  public function getRangeMin(): ?float
588  {
589  return $this->range_min;
590  }
591 
592  public function getRangeMinBase()
593  {
594  if ($this->getUnit() !== null) {
595  return ilMath::_mul($this->getRangeMin(), $this->getUnit()->getFactor(), 100);
596  }
597 
598  return $this->getRangeMin();
599  }
600 
601  public function setRangeMax(?string $range_max): void
602  {
603  if ($range_max === null) {
604  return;
605  }
606 
607  $math = new EvalMath();
608  $math->suppress_errors = true;
609  $this->range_max = (float) $math->evaluate($range_max);
610  }
611 
612  public function getRangeMax(): ?float
613  {
614  return $this->range_max;
615  }
616 
617  public function getRangeMaxBase()
618  {
619  if ($this->getUnit() !== null) {
620  return ilMath::_mul($this->getRangeMax(), $this->getUnit()->getFactor(), 100);
621  }
622 
623  return $this->getRangeMax();
624  }
625 
626  public function setTolerance($tolerance): void
627  {
628  $this->tolerance = $tolerance;
629  }
630 
631  public function getTolerance(): float
632  {
633  return $this->tolerance;
634  }
635 
636  public function setUnit(?assFormulaQuestionUnit $unit): void
637  {
638  $this->unit = $unit;
639  }
640 
641  public function getUnit(): ?assFormulaQuestionUnit
642  {
643  return $this->unit;
644  }
645 
646  public function setFormula(?string $formula): void
647  {
648  $this->formula = $formula;
649  }
650 
651  public function getFormula(): ?string
652  {
653  return $this->formula;
654  }
655 
656  public function setPoints(float $points): void
657  {
658  $this->points = $points;
659  }
660 
661  public function getPoints(): float
662  {
663  return $this->points;
664  }
665 
666  public function setRatingSimple(bool $rating_simple): void
667  {
668  $this->rating_simple = $rating_simple;
669  }
670 
671  public function getRatingSimple(): bool
672  {
673  return $this->rating_simple;
674  }
675 
676  public function setRatingSign(float $rating_sign): void
677  {
678  $this->rating_sign = $rating_sign;
679  }
680 
681  public function getRatingSign(): float
682  {
683  return $this->rating_sign;
684  }
685 
686  public function setRatingValue(float $rating_value): void
687  {
688  $this->rating_value = $rating_value;
689  }
690 
691  public function getRatingValue(): float
692  {
693  return $this->rating_value;
694  }
695 
696  public function setRatingUnit(float $rating_unit): void
697  {
698  $this->rating_unit = $rating_unit;
699  }
700 
701  public function getRatingUnit(): float
702  {
703  return $this->rating_unit;
704  }
705 
706  public function setPrecision(float $precision): void
707  {
708  $this->precision = $precision;
709  }
710 
711  public function getPrecision(): int
712  {
713  return $this->precision;
714  }
715 
716  public function setResultType(int $a_result_type): void
717  {
718  $this->result_type = $a_result_type;
719  }
720 
721  public function getResultType(): int
722  {
723  return (int) $this->result_type;
724  }
725 
726  public function setRangeMaxTxt(string $range_max_txt): void
727  {
728  $this->range_max_txt = $range_max_txt;
729  }
730 
731  public function getRangeMaxTxt(): string
732  {
733  return $this->range_max_txt;
734  }
735 
736  public function setRangeMinTxt(string $range_min_txt): void
737  {
738  $this->range_min_txt = $range_min_txt;
739  }
740 
741  public function getRangeMinTxt(): string
742  {
743  return $this->range_min_txt;
744  }
745 
746  public static function getResultTypeByQstId($a_qst_id, $a_result)
747  {
748  global $DIC;
749  $ilDB = $DIC['ilDB'];
750 
751  $res = $ilDB->queryF(
752  '
753  SELECT result_type
754  FROM il_qpl_qst_fq_res
755  WHERE question_fi = %s
756  AND result = %s',
757  ['integer', 'text'],
758  [$a_qst_id, $a_result]
759  );
760 
761  $row = $ilDB->fetchAssoc($res);
762 
763  return $row['result_type'];
764  }
765 
766  public static function isCoprimeFraction($numerator, $denominator): bool
767  {
768  $gcd = self::getGreatestCommonDivisor(abs($numerator), abs($denominator));
769 
770  return $gcd == 1 ? true : false;
771  }
772 
773  public static function convertDecimalToCoprimeFraction($decimal_value, $tolerance = 1.e-9)
774  {
775  if (empty($decimal_value)) {
776  return '';
777  }
778 
779  $to_string = (string) $decimal_value;
780  $is_negative = strpos($to_string, '-') === 0;
781  if ($is_negative) {
782  $decimal_value = substr($decimal_value, 1);
783  }
784  $h1 = 1;
785  $h2 = 0;
786  $k1 = 0;
787  $k2 = 1;
788  $b = 1 / $decimal_value;
789  do {
790  $b = 1 / $b;
791  $a = floor($b);
792  $aux = $h1;
793  $h1 = $a * $h1 + $h2;
794  $h2 = $aux;
795  $aux = $k1;
796  $k1 = $a * $k1 + $k2;
797  $k2 = $aux;
798  $b = $b - $a;
799  } while ((abs($decimal_value - $h1 / $k1) > $decimal_value * $tolerance) || ($k1 < 0 || $b < 0));
800  if ($k1 == 1) {
801  $result = $h1;
802  $checkResult = $h1;
803  } else {
804  $result = "$h1/$k1";
805  $checkResult = ($h1 / $k1);
806  }
807  if ($is_negative) {
808  $result = '-' . $result;
809  $checkResult = ($h1 / $k1) * -1;
810  }
811  if ($to_string == $checkResult . '' || $checkResult . '' == $result) {
812  return $result;
813  } else {
814  return [$to_string,$result];
815  }
816  }
817 
818  public static function getGreatestCommonDivisor($a, $b)
819  {
820  if ($b > 0) {
821  return self::getGreatestCommonDivisor($b, $a % $b);
822  } else {
823  return $a;
824  }
825  }
826 
827 
828  public function getAvailableResultUnits($question_id): array
829  {
830  global $DIC;
831  $ilDB = $DIC['ilDB'];
832 
833  $res = $ilDB->queryF(
834  '
835  SELECT * FROM il_qpl_qst_fq_res_unit
836  WHERE question_fi = %s
837  ORDER BY result',
838  ['integer'],
839  [$question_id]
840  );
841 
842 
843  while ($row = $ilDB->fetchAssoc($res)) {
844  $this->available_units[$row['result']][] = $row['unit_fi'] ;
845  }
846 
847  return $this->available_units;
848  }
849 }
static _add($left_operand, $right_operand, int $scale=50)
$res
Definition: ltiservices.php:66
substituteFormula(array $variables, array $results)
calculateFormula($variables, $results, $question_id=0, $use_precision=true)
static _div($left_operand, $right_operand, int $scale=50)
isInTolerance($user_answer, $expected, $tolerated_percentage)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
transformAnswerValueAccordingToType(string $value, ?assFormulaQuestionUnit $unit)
static getResultTypeByQstId($a_qst_id, $a_result)
getResultInfo($variables, $results, $value, $unit, $units)
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
static isCoprimeFraction($numerator, $denominator)
static _sub($left_operand, $right_operand, int $scale=50)
findValidRandomVariables($variables, $results)
__construct(private string $result, private ?string $range_min_txt, private ?string $range_max_txt, private float $tolerance, private ?assFormulaQuestionUnit $unit, private ?string $formula, private float $points, private int $precision, private bool $rating_simple=true, private ?float $rating_sign=null, private ?float $rating_value=null, private ?float $rating_unit=null, private float $result_type=0)
global $DIC
Definition: shib_login.php:26
isCorrect($variables, $results, $value, $unit=null)
$results
calculateCorrectResult(array $variables, array $results)
getReachedPoints(array $variables, array $results, string $answer_value, ?assFormulaQuestionUnit $answer_unit, array $units)
$a
thx to https://mlocati.github.io/php-cs-fixer-configurator for the examples
static _mul($left_operand, $right_operand, int $scale=50)
setUnit(?assFormulaQuestionUnit $unit)
static convertDecimalToCoprimeFraction($decimal_value, $tolerance=1.e-9)