ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
class.assFormulaQuestionResult.php
Go to the documentation of this file.
1<?php
2
19use ILIAS\Refinery\Factory as Refinery;
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
35 private Refinery $refinery;
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}
Builds data types.
Definition: Factory.php:36
return true
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
isInTolerance($user_answer, $expected, $tolerated_percentage)
static getResultTypeByQstId($a_qst_id, $a_result)
calculateFormula($variables, $results, $question_id=0, $use_precision=true)
static isCoprimeFraction($numerator, $denominator)
getResultInfo($variables, $results, $value, $unit, $units)
calculateCorrectResult(array $variables, array $results)
setUnit(?assFormulaQuestionUnit $unit)
__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)
substituteFormula(array $variables, array $results)
static convertDecimalToCoprimeFraction($decimal_value, $tolerance=1.e-9)
getReachedPoints(array $variables, array $results, string $answer_value, ?assFormulaQuestionUnit $answer_unit, array $units)
findValidRandomVariables($variables, $results)
transformAnswerValueAccordingToType(string $value, ?assFormulaQuestionUnit $unit)
isCorrect($variables, $results, $value, $unit=null)
language handling
static _sub($left_operand, $right_operand, int $scale=50)
static _add($left_operand, $right_operand, int $scale=50)
static _div($left_operand, $right_operand, int $scale=50)
static _mul($left_operand, $right_operand, int $scale=50)
$res
Definition: ltiservices.php:69
$a
thx to https://mlocati.github.io/php-cs-fixer-configurator for the examples
$results
if(!file_exists('../ilias.ini.php'))
global $DIC
Definition: shib_login.php:26