From 031f3a1d4b310fe871405b197f02f3cd45d0d32d Mon Sep 17 00:00:00 2001 From: Shamim Rezaie Date: Wed, 27 Nov 2019 20:49:38 +1100 Subject: [PATCH 1/6] MDL-67151 core: format_float can auto detect number of decimal points --- lib/moodlelib.php | 12 ++++++++++-- lib/tests/moodlelib_test.php | 8 ++++++++ lib/upgrade.txt | 3 +++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/lib/moodlelib.php b/lib/moodlelib.php index d10f31d7a97..1b69c4a1281 100644 --- a/lib/moodlelib.php +++ b/lib/moodlelib.php @@ -8630,9 +8630,10 @@ function generate_password($maxlen=10) { * then it will display '5.4' instead of '5.400' or '5' instead of '5.000'. * * @param float $float The float to print - * @param int $decimalpoints The number of decimal places to print. + * @param int $decimalpoints The number of decimal places to print. -1 is a special value for auto detect (full precision). * @param bool $localized use localized decimal separator - * @param bool $stripzeros If true, removes final zeros after decimal point + * @param bool $stripzeros If true, removes final zeros after decimal point. It will be ignored and the trailing zeros after + * the decimal point are always striped if $decimalpoints is -1. * @return string locale float */ function format_float($float, $decimalpoints=1, $localized=true, $stripzeros=false) { @@ -8644,6 +8645,13 @@ function format_float($float, $decimalpoints=1, $localized=true, $stripzeros=fal } else { $separator = '.'; } + if ($decimalpoints == -1) { + // The following counts the number of decimals. + // It is safe as both floatval() and round() functions have same behaviour when non-numeric values are provided. + $floatval = floatval($float); + for ($decimalpoints = 0; $floatval != round($float, $decimalpoints); $decimalpoints++); + } + $result = number_format($float, $decimalpoints, $separator, ''); if ($stripzeros) { // Remove zeros and final dot if not needed. diff --git a/lib/tests/moodlelib_test.php b/lib/tests/moodlelib_test.php index b65af4012b3..82db58e3059 100644 --- a/lib/tests/moodlelib_test.php +++ b/lib/tests/moodlelib_test.php @@ -2249,6 +2249,14 @@ class core_moodlelib_testcase extends advanced_testcase { // Custom number of decimal places. $this->assertEquals('5.43000', format_float(5.43, 5)); + // Auto detect the number of decimal places. + $this->assertEquals('5.43', format_float(5.43, -1)); + $this->assertEquals('5.43', format_float(5.43000, -1)); + $this->assertEquals('5', format_float(5, -1)); + $this->assertEquals('5', format_float(5.0, -1)); + $this->assertEquals('0.543', format_float('5.43e-1', -1)); + $this->assertEquals('0.543', format_float('5.43000e-1', -1)); + // Option to strip ending zeros after rounding. $this->assertEquals('5.43', format_float(5.43, 5, true, true)); $this->assertEquals('5', format_float(5.0001, 3, true, true)); diff --git a/lib/upgrade.txt b/lib/upgrade.txt index b65a321b348..9ea25900d87 100644 --- a/lib/upgrade.txt +++ b/lib/upgrade.txt @@ -1,6 +1,9 @@ This files describes API changes in core libraries and APIs, information provided here is intended especially for developers. +=== 3.8.1 === +format_float() now accepts a special value (-1) as the $decimalpoints parameter which means auto-detecting number of decimal points. + === 3.8 === * The rotate_image function has been added to the stored_file class (MDL-63349) * The yui checknet module is removed. Call \core\session\manager::keepalive instead. From 481ad40e0e6cf60800524dfa9fb1bc766e74ac72 Mon Sep 17 00:00:00 2001 From: Shamim Rezaie Date: Fri, 22 Nov 2019 16:50:23 +1100 Subject: [PATCH 2/6] MDL-67151 forms: Support for the scientific format in the float element --- lib/form/float.php | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/form/float.php b/lib/form/float.php index 8f375c2b986..e1685f207de 100644 --- a/lib/form/float.php +++ b/lib/form/float.php @@ -175,12 +175,18 @@ class MoodleQuickForm_float extends MoodleQuickForm_text { */ private function format_float($value) { if (is_numeric($value)) { - if ($value > 0) { - $decimals = strlen($value) - strlen(floor($value)) - 1; + // We want to keep trailing zeros after the decimal point if there is any. + // Therefore we cannot just call format_float() and pass -1 as the number of decimal points. + $pieces = preg_split('/E/i', $value); // In case it is in the scientific format. + $decimalpos = strpos($pieces[0], '.'); + if ($decimalpos !== false) { + $decimalpart = substr($pieces[0], $decimalpos + 1); + $decimals = strlen($decimalpart); } else { - $decimals = strlen($value) - strlen(ceil($value)) - 1; + $decimals = 0; } - $value = format_float($value, $decimals); + $pieces[0] = format_float($pieces[0], $decimals); + $value = implode('E', $pieces); } return $value; } From bb511f30d607d8ea86bc0d541f8e26b524a86f4d Mon Sep 17 00:00:00 2001 From: Shamim Rezaie Date: Fri, 22 Nov 2019 19:43:09 +1100 Subject: [PATCH 3/6] MDL-67151 core_question: Support scientific format at question preview --- lib/questionlib.php | 2 +- question/tests/behat/preview_question.feature | 15 ++++++--------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/lib/questionlib.php b/lib/questionlib.php index 7aee57fb94e..8566321a1e1 100644 --- a/lib/questionlib.php +++ b/lib/questionlib.php @@ -806,7 +806,7 @@ function question_preview_url($questionid, $preferredbehaviour = null, } if (!is_null($maxmark)) { - $params['maxmark'] = format_float($maxmark, strlen($maxmark), true, true); + $params['maxmark'] = format_float($maxmark, -1); } if (!is_null($displayoptions)) { diff --git a/question/tests/behat/preview_question.feature b/question/tests/behat/preview_question.feature index cba500906f5..e3630e34a39 100644 --- a/question/tests/behat/preview_question.feature +++ b/question/tests/behat/preview_question.feature @@ -1,4 +1,4 @@ -@core @core_question +@core @core_question @javascript @_switch_window Feature: A teacher can preview questions in the question bank In order to ensure the questions are properly created As a teacher @@ -26,7 +26,6 @@ Feature: A teacher can preview questions in the question bank When I choose "Preview" action for "Test question to be previewed" in the question bank And I switch to "questionpreview" window - @javascript @_switch_window Scenario: Question preview shows the question and other information Then the state of "What is pi to two d.p.?" question is shown as "Not yet answered" And I should see "Marked out of 1.00" @@ -34,19 +33,16 @@ Feature: A teacher can preview questions in the question bank And I should see "Attempt options" And I should see "Display options" - @javascript @_switch_window Scenario: Preview lets the teacher see what happens when an answer is saved When I set the field "Answer:" to "1" And I press "Save" Then the state of "What is pi to two d.p.?" question is shown as "Answer saved" - @javascript @_switch_window Scenario: Preview lets the teacher see what happens when an answer is submitted When I set the field "Answer:" to "3.14" And I press "Submit and finish" Then the state of "What is pi to two d.p.?" question is shown as "Correct" - @javascript @_switch_window Scenario: Preview lets the teacher see what happens with different review options Given I set the field "Answer:" to "3.14" And I press "Submit and finish" @@ -56,7 +52,6 @@ Feature: A teacher can preview questions in the question bank Then the state of "What is pi to two d.p.?" question is shown as "Complete" And I should see "1.00000" - @javascript @_switch_window Scenario: Preview lets the teacher see what happens with different behaviours When I set the field "How questions behave" to "Immediate feedback" And I set the field "Marked out of" to "3" @@ -67,18 +62,20 @@ Feature: A teacher can preview questions in the question bank And I should see "Mark 0.00 out of 3.00" And I should see "Not accurate enough." - @javascript @_switch_window Scenario: Preview lets the teacher "Start again" while previewing Given I set the field "Answer:" to "1" And I press "Submit and finish" When I press "Start again" Then the state of "What is pi to two d.p.?" question is shown as "Not yet answered" - @javascript @_switch_window Scenario: Preview lets the teacher "Fill in correct response" while previewing When I press "Fill in correct responses" Then the field "Answer:" matches value "3.14" - @javascript @_switch_window Scenario: Preview has an option to export the individual quesiton. Then following "Download this question in Moodle XML format" should download between "1000" and "2500" bytes + + Scenario: Preview a question with very small grade + When I set the field "Marked out of" to "0.00000123456789" + And I press "Start again with these options" + Then the field "Marked out of" matches value "0.00000123456789" From fcf199b0ec314a3ec6909e3dee977848c4f4714f Mon Sep 17 00:00:00 2001 From: Shamim Rezaie Date: Fri, 22 Nov 2019 17:50:50 +1100 Subject: [PATCH 4/6] MDL-67151 qtype_numerical: Support for the scientific format --- .../type/numerical/edit_numerical_form.php | 2 +- .../type/numerical/tests/behat/edit.feature | 20 ++++++++++++++++--- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/question/type/numerical/edit_numerical_form.php b/question/type/numerical/edit_numerical_form.php index 6788058255f..c54e06d9563 100644 --- a/question/type/numerical/edit_numerical_form.php +++ b/question/type/numerical/edit_numerical_form.php @@ -212,7 +212,7 @@ class qtype_numerical_edit_form extends question_edit_form { $question->tolerance[$key] = $answer->tolerance; if (is_numeric($question->answer[$key])) { - $question->answer[$key] = format_float($question->answer[$key], strlen($question->answer[$key]), true, true); + $question->answer[$key] = format_float($question->answer[$key], -1); } $key++; diff --git a/question/type/numerical/tests/behat/edit.feature b/question/type/numerical/tests/behat/edit.feature index a365876e32d..ea9691983a3 100644 --- a/question/type/numerical/tests/behat/edit.feature +++ b/question/type/numerical/tests/behat/edit.feature @@ -20,14 +20,14 @@ Feature: Test editing a Numerical question And the following "questions" exist: | questioncategory | qtype | name | template | | Test questions | numerical | Numerical for editing | pi | - And the following "language customisations" exist: + + Scenario: Edit a Numerical question when using a custom decimal separator + Given the following "language customisations" exist: | component | stringid | value | | core_langconfig | decsep | # | And I log in as "teacher1" And I am on "Course 1" course homepage And I navigate to "Question bank" in current page administration - - Scenario: Edit a Numerical question When I choose "Edit question" action for "Numerical for editing" in the question bank Then the field "id_answer_0" matches value "3#14" When I set the following fields to these values: @@ -47,3 +47,17 @@ Feature: Test editing a Numerical question | id_answer_3 | 3,01 | And I press "id_submitbutton" Then I should see "Edited Numerical name" + + Scenario: Edit a Numerical question with very small answer + Given I log in as "teacher1" + And I am on "Course 1" course homepage + And I navigate to "Question bank" in current page administration + When I choose "Edit question" action for "Numerical for editing" in the question bank + And I set the following fields to these values: + | id_answer_0 | 0.00000123456789 | + | id_tolerance_1 | 0.0000123456789 | + And I press "id_submitbutton" + And I choose "Edit question" action for "Numerical for editing" in the question bank + Then the following fields match these values: + | id_answer_0 | 0.00000123456789 | + | id_tolerance_1 | 0.0000123456789 | From 910c2ab7b447447185c7ad67040e1c66cd7d2d2d Mon Sep 17 00:00:00 2001 From: Shamim Rezaie Date: Mon, 25 Nov 2019 15:24:48 +1100 Subject: [PATCH 5/6] MDL-67151 qtype_calculated: Support for the scientific format --- question/type/calculated/datasetitems_form.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/question/type/calculated/datasetitems_form.php b/question/type/calculated/datasetitems_form.php index 21ac15f32fa..a29cc7bfe37 100644 --- a/question/type/calculated/datasetitems_form.php +++ b/question/type/calculated/datasetitems_form.php @@ -410,7 +410,7 @@ class question_dataset_dependent_items_form extends question_wizard_form { if ($this->_form->getElementType("number[{$j}]") == 'hidden') { // Some of the number elements are from the float type and some are from the hidden type. // We need to manually handle localised floats for hidden elements. - $value = format_float($value, strlen($value), true, true); + $value = format_float($value, -1); } $formdata["number[{$j}]"] = $value; $formdata["definition[{$j}]"] = $defid; @@ -449,7 +449,7 @@ class question_dataset_dependent_items_form extends question_wizard_form { if ($this->_form->getElementType("number[{$j}]") == 'hidden') { // Some of the number elements are from the float type and some are from the hidden type. // We need to manually handle localised floats for hidden elements. - $value = format_float($value, strlen($value), true, true); + $value = format_float($value, -1); } $formdata["number[{$j}]"] = $value; $formdata["definition[{$j}]"] = $defid; From 163bff4a184cf2e7a4d6a9b835daec818d7e21d5 Mon Sep 17 00:00:00 2001 From: Shamim Rezaie Date: Mon, 25 Nov 2019 17:07:11 +1100 Subject: [PATCH 6/6] MDL-67151 qtype_calculatedsimple: Support for the scientific format --- question/type/calculatedsimple/edit_calculatedsimple_form.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/question/type/calculatedsimple/edit_calculatedsimple_form.php b/question/type/calculatedsimple/edit_calculatedsimple_form.php index a48372e02fc..7af36e2d43d 100644 --- a/question/type/calculatedsimple/edit_calculatedsimple_form.php +++ b/question/type/calculatedsimple/edit_calculatedsimple_form.php @@ -508,8 +508,7 @@ class qtype_calculatedsimple_edit_form extends qtype_calculated_edit_form { $mform->addElement('hidden', "number[{$j}]", ''); $mform->setType("number[{$j}]", PARAM_LOCALISEDFLOAT); // Localisation handling has to be done manually. if (isset($this->formdata["number[{$j}]"])) { - $number = $this->formdata["number[{$j}]"]; - $this->formdata["number[{$j}]"] = format_float($number, strlen($number), true, true); + $this->formdata["number[{$j}]"] = format_float($this->formdata["number[{$j}]"], -1); } }