]> git.mjollnir.org Git - moodle.git/commitdiff
Bug 5968 - Improvements to the numerical question type. You can now display feedback...
authortjhunt <tjhunt>
Wed, 12 Jul 2006 17:49:14 +0000 (17:49 +0000)
committertjhunt <tjhunt>
Wed, 12 Jul 2006 17:49:14 +0000 (17:49 +0000)
question/format/gift/format.php
question/type/numerical/editquestion.html
question/type/numerical/editquestion.php
question/type/numerical/questiontype.php

index 0eb0b17a42f2f7e1c146c60b3e1d9c109703ed43..c3a873d18ac7d0ed2f8f2f865bcf2871ae1bf291 100755 (executable)
@@ -393,6 +393,14 @@ class qformat_gift extends qformat_default {
                 // Note similarities to ShortAnswer
                 $answertext = substr($answertext, 1); // remove leading "#"
 
+                // If there is feedback for a wrong answer, store it for now.
+                if (($pos = strpos($answertext, '~')) !== false) {
+                    $wrongfeedback = substr($answertext, $pos);
+                    $answertext = substr($answertext, 0, $pos);
+                } else {
+                    $wrongfeedback = '';
+                }
+
                 $answers = explode("=", $answertext);
                 if (isset($answers[0])) {
                     $answers[0] = trim($answers[0]);
@@ -454,6 +462,14 @@ class qformat_gift extends qformat_default {
                     $question->tolerance[$key] = $tol;
                 } // end foreach
 
+                if ($wrongfeedback) {
+                    $key += 1;
+                    $question->fraction[$key] = 0;
+                    $question->feedback[$key] = $this->commentparser($wrongfeedback);
+                    $question->answer[$key] = '';
+                    $question->tolerance[$key] = '';
+                }
+
                 //$question->defaultgrade = 1;
                 //$question->image = "";   // No images with this format
                 //$question->multiplier = array(); // no numeric multipliers with GIFT
@@ -571,12 +587,19 @@ function writequestion( $question ) {
         $expout .= "}\n";
         break;
     case NUMERICAL:
-        $answer = array_pop( $question->options->answers );
-        $tolerance = $answer->tolerance;
-        $min = $answer->answer - $tolerance;
-        $max = $answer->answer + $tolerance;
-        $expout .= "::".$question->name."::".$tfname.$this->repchar( $question->questiontext, $textformat )."{\n";
-        $expout .= "\t#".$min."..".$max."#".$this->repchar( $answer->feedback )."\n";
+        $expout .= "::".$question->name."::".$tfname.$this->repchar( $question->questiontext, $textformat )."{#\n";
+        foreach ($question->options->answers as $answer) {
+            // DONOTCOMMIT
+            echo '<pre>';
+            var_export($answer);
+            echo '</pre>';
+            
+            if ($answer->answer != '') {
+                $expout .= "\t=".$answer->answer.":".(float)$answer->tolerance."#".$this->repchar( $answer->feedback )."\n";
+            } else {
+                $expout .= "\t~#".$this->repchar( $answer->feedback )."\n";
+            }
+        }
         $expout .= "}\n";
         break;
     case MATCH:
index 01ce543a1a87fb03e771dd4dd6de05a0dbc7d80d..e48dda35f993fd75d5c6d8c3b62590748ab2009b 100644 (file)
@@ -2,20 +2,20 @@
 <center>
 <table cellpadding="5">
 <tr valign="top">
-    <td align="right"><b><?php  print_string("category", "quiz") ?>:</b></td>
+    <td align="right"><b><?php print_string("category", "quiz") ?>:</b></td>
     <td align="left">
-    <?php   question_category_select_menu($course->id, true, true, $question->category); ?>
+    <?php question_category_select_menu($course->id, true, true, $question->category); ?>
     </td>
 </tr>
 <tr valign="top">
-    <td align="right"><b><?php  print_string("questionname", "quiz") ?>:</b></td>
+    <td align="right"><b><?php print_string("questionname", "quiz") ?>:</b></td>
     <td align="left">
-        <input type="text" name="name" size="50" value="<?php  p($question->name) ?>" alt="<?php  print_string("questionname", "quiz") ?>" />
-        <?php  if (isset($err["name"])) formerr($err["name"]); ?>
+        <input type="text" name="name" size="50" value="<?php p($question->name) ?>" alt="<?php print_string("questionname", "quiz") ?>" />
+        <?php if (isset($err["name"])) formerr($err["name"]); ?>
     </td>
 </tr>
 <tr valign="top">
-    <td align="right"><b><?php  print_string("question", "quiz") ?>:</b>
+    <td align="right"><b><?php print_string("question", "quiz") ?>:</b>
     <br />
     <br />
     <br />
@@ -30,7 +30,7 @@
     </font>
     </td>
     <td align="left">
-        <?php  if (isset($err["questiontext"])) {
+        <?php if (isset($err["questiontext"])) {
                formerr($err["questiontext"]);
                echo "<br />";
            }
     </td>
 </tr>
 <tr valign="top">
-    <td align="right"><b><?php  print_string("imagedisplay", "quiz") ?>:</b></td>
+    <td align="right"><b><?php print_string("imagedisplay", "quiz") ?>:</b></td>
     <td align="left">
-    <?php   if (empty($images)) {
+    <?php
+        if (empty($images)) {
             print_string("noimagesyet");
         } else {
             choose_from_menu($images, "image", "$question->image", get_string("none"),"","");
     </td>
 </tr>
 <tr valign="top">
-    <td align="right"><b><?php  print_string("defaultgrade", "quiz") ?>:</b></td>
+    <td align="right"><b><?php print_string("defaultgrade", "quiz") ?>:</b></td>
     <td align="left">
-        <input type="text" name="defaultgrade" size="3" value="<?php  p($question->defaultgrade) ?>" alt="<?php  print_string("defaultgrade", "quiz") ?>" />
+        <input type="text" name="defaultgrade" size="3" value="<?php p($question->defaultgrade) ?>" alt="<?php print_string("defaultgrade", "quiz") ?>" />
 
-        <?php  if (isset($err["defaultgrade"])) formerr($err["defaultgrade"]); ?>
+        <?php if (isset($err["defaultgrade"])) formerr($err["defaultgrade"]); ?>
     </td>
 </tr>
 <tr valign="top">
-    <td align="right"><b><?php  print_string("penaltyfactor", "quiz") ?>:</b></td>
+    <td align="right"><b><?php print_string("penaltyfactor", "quiz") ?>:</b></td>
     <td align="left">
-        <input type="text" name="penalty" size="3" value="<?php  p($question->penalty) ?>" alt="<?php  print_string("penaltyfactor", "quiz") ?>" />
+        <input type="text" name="penalty" size="3" value="<?php p($question->penalty) ?>" alt="<?php print_string("penaltyfactor", "quiz") ?>" />
         <?php helpbutton('penalty', get_string('penalty', 'quiz'), 'quiz'); ?>
-        <?php  if (isset($err["penalty"])) formerr($err["penalty"]); ?>
+        <?php if (isset($err["penalty"])) formerr($err["penalty"]); ?>
     </td>
 </tr>
+<!-- Answers. -->
+<?php
+    for ($i=1; $i<=count($answers); $i++) {
+        $answer = $answers[$i-1];
+?>
 <tr valign="top">
-    <td align="right"><b><?php  print_string("correctanswer", "quiz") ?>:</b></td>
+    <td align="right"><b><?php echo get_string("answer", "quiz")." $i";  ?>:</b></td>
     <td align="left">
-        <input align="left" type="text" id="correct0" name="answer[]" size="10" value="<?php p($answer->answer) ?>" alt="<?php  print_string("correctanswer", "quiz") ?>" />
+        <?php
+            if ($answer->answer === '' && !isset($answer->tolerance) && !isset($answer->fraction)) {
+                $answervalue = '';
+                $answertolerance = '';
+                $fractionval = 0;
+                $feedbacktext = '';
+            } else {
+                $answervalue = $answer->answer;
+                $answertolerance = $answer->tolerance;
+                $fractionval = $answer->fraction;
+                $feedbacktext = $answer->feedback;
+            }
+        ?>
+        <input type="text" name="answer[]" size="25" value="<?php p($answervalue); ?>" />&nbsp;&nbsp;
+        <?php echo get_string("acceptederror", "quiz"); ?>&nbsp;<input type="text" name="tolerance[]" size="15" value="<?php p($answertolerance) ?>" />&plusmn;&nbsp;&nbsp;
+        <?php print_string("grade");
+           echo ":&nbsp;";
+           choose_from_menu($gradeoptions, "fraction[]", $fractionval,""); ?>
+        <br />
     </td>
 </tr>
 <tr valign="top">
-    <td align="right"><b><?php  print_string("acceptederror", "quiz"); ?>:</b></td>
+    <td align="right"><b><?php print_string("feedback", "quiz") ?>:</b></td>
     <td align="left">
-        <input align="left" type="text" id="acceptederror0" name="tolerance[]" size="10" value="<?php p($tolerance); ?>" alt="<?php  print_string("acceptederror", "quiz"); ?>" />&plusmn;
-        <input type="hidden" name="fraction[]" value="1" />
+        <textarea name="feedback[]" rows="2" cols="50"><?php p($feedbacktext) ?></textarea>
     </td>
 </tr>
 <tr valign="top">
-    <td align="right"><b><?php  print_string("feedback", "quiz") ?>:</b></td>
-    <td align="left">
-        <textarea name="feedback[]" rows="2" cols="50"><?php  p($answer->feedback); ?></textarea>
-    </td>
+    <td colspan="2">&nbsp;</td>
 </tr>
+<?php
+    }
+?>
+<!-- Units. -->
 <tr valign="top">
-<td align="right"><b><?php  print_string("unit", "quiz") ?>:</b></td>
+<td align="right"><b><?php print_string("unit", "quiz") ?>:</b></td>
     <td align="left"><?php
     if (isset($units[0]) && 1.0 === (float)$units[0]->multiplier) {
         $unit = $units[0]->unit;
     ?>
     <input type="hidden" name="multiplier[]" value="<?php p($multiplier) ?>" />
     <input align="left" type="text" id="defaultunit" name="unit[]" size="10" value="<?php p($unit) ?>" alt="<?php print_string("unit", "quiz") ?>" />
-    <b>(<?php  print_string("optional", "quiz") ?>)</b>
+    <b>(<?php print_string("optional", "quiz") ?>)</b>
     </td>
 </tr>
 <tr valign="top">
 <td></td>
-<td align="left"><b><?php  print_string("alternativeunits", "quiz") ?>:</b></td>
+<td align="left"><b><?php print_string("alternativeunits", "quiz") ?>:</b></td>
 <td></td>
 </tr>
 <?php
@@ -132,11 +156,11 @@ for ($i = 1; $i < 6; $i++) {
 <tr valign="top">
 <td></td>
     <td align="left">
-        <b><?php  print_string("multiplier", "quiz") ?>:</b>
-        <input type="text" size="10" name="multiplier[]" value="<?php  p($multiplier) ?>"
+        <b><?php print_string("multiplier", "quiz") ?>:</b>
+        <input type="text" size="10" name="multiplier[]" value="<?php p($multiplier) ?>"
                 alt="<?php print_string("multiplier", "quiz") ?>" />
         <b>&nbsp;&nbsp;&nbsp;<?php print_string("unit", "quiz") ?>:</b>
-        <input type="text" name="unit[]" size="5" value="<?php  p($unit) ?>" />
+        <input type="text" name="unit[]" size="5" value="<?php p($unit) ?>" />
     </td>
 </tr>
 <?php
index e746437252d4f3f80c36bb627a0905a05e8e31a1..7b5c87730874b8a4ce7926b35ccc670e6d151912 100644 (file)
@@ -2,26 +2,29 @@
 
     // Get all the extra information if we're editing
     if (!empty($question->id) && isset($question->qtype) &&
-     $QTYPES[$question->qtype]->get_question_options($question)) {
-        $answer = array_values($question->options->answers);
-        usort($answer, create_function('$a, $b',
-         'if ($a->fraction == $a->fraction) { return 0; }' .
-         'else { return $a->fraction < $b->fraction ? -1 : 1; }'));
-        $answer = $answer[0]; // Get the answer with the highest fraction (i.e. 1)
+            $QTYPES[$question->qtype]->get_question_options($question)) {
+
+        $answers = array_values($question->options->answers);
         $units  = array_values($question->options->units);
         usort($units, create_function('$a, $b', // make sure the default unit is at index 0
-         'if (1.0 === (float)$a->multiplier) { return -1; } else '.
-         'if (1.0 === (float)$b->multiplier) { return 1; } else { return 0; }'));
-        $tolerance = $answer->tolerance;
+                'if (1.0 === (float)$a->multiplier) { return -1; } else '.
+                'if (1.0 === (float)$b->multiplier) { return 1; } else { return 0; }'));
     } else {
-        $answer   = new stdClass;
-        $answer->answer   = '';
-        $answer->feedback = '';
+        $answers = array();
         $units     = array();
-        $tolerance = '';
+    }
+
+    // Add blank answers to make the number up to QUESTION_NUMANS
+    // or one more than current, if there are already lots.
+    $emptyanswer = new stdClass;
+    $emptyanswer->answer = '';
+    $i = count($answers);
+    $limit = QUESTION_NUMANS;
+    $limit = $limit <= $i ? $i+1 : $limit;
+    for (; $i < $limit; $i++) {
+        $answers[] = $emptyanswer;
     }
 
     print_heading_with_help(get_string("editingnumerical", "quiz"), "numerical", "quiz");
     require("$CFG->dirroot/question/type/numerical/editquestion.html");
-
 ?>
index 0e321cc8bbc92eddd336bb4f91665a88db3e590e..a8e8427a36103ba374cc65f66c3a5cff0a9a5354 100644 (file)
@@ -1,21 +1,22 @@
-<?php  // $Id$
-
-/////////////////
-/// NUMERICAL ///
-/////////////////
-
-/// QUESTION TYPE CLASS //////////////////
-
-///
-/// This class contains some special features in order to make the
-/// question type embeddable within a multianswer (cloze) question
-///
-
-/// This question type behaves like shortanswer in most cases.
-/// Therefore, it extends the shortanswer question type...
+<?php
+/**
+ * @version $Id$
+ * @author Martin Dougiamas and many others. Tim Hunt.
+ * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
+ * @package question
+ *//** */
 
 require_once("$CFG->dirroot/question/type/shortanswer/questiontype.php");
 
+/**
+ * NUMERICAL QUESTION TYPE CLASS
+ *
+ * This class contains some special features in order to make the
+ * question type embeddable within a multianswer (cloze) question
+ *
+ * This question type behaves like shortanswer in most cases.
+ * Therefore, it extends the shortanswer question type...
+ */
 class question_numerical_qtype extends question_shortanswer_qtype {
 
     function name() {
@@ -45,9 +46,9 @@ class question_numerical_qtype extends question_shortanswer_qtype {
             foreach($question->options->answers as $key => $val) {
                 $answer = trim($val->answer);
                 $length = strlen($defaultunit->unit);
-                if (substr($answer, -$length) == $defaultunit->unit) {
+                if ($length && substr($answer, -$length) == $defaultunit->unit) {
                     $question->options->answers[$key]->answer =
-                     substr($answer, 0, strlen($answer)-$length);
+                            substr($answer, 0, strlen($answer)-$length);
                 }
             }
         }
@@ -88,11 +89,11 @@ class question_numerical_qtype extends question_shortanswer_qtype {
         return $unit;
     }
 
+    /**
+     * Save the units and the answers associated with this question.
+     */
     function save_question_options($question) {
-        // save_question_options supports the definition of multiple answers
-        // for numerical questions. This is not currently used by the editing
-        // interface, but the GIFT format supports it. The multianswer qtype,
-        // for example can make use of this feature.
+        
         // Get old versions of the objects
         if (!$oldanswers = get_records("question_answers", "question", $question->id)) {
             $oldanswers = array();
@@ -102,6 +103,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
             $oldoptions = array();
         }
 
+        // Save the units.
         $result = $this->save_numerical_units($question);
         if (isset($result->error)) {
             return $result;
@@ -111,10 +113,17 @@ class question_numerical_qtype extends question_shortanswer_qtype {
 
         // Insert all the new answers
         foreach ($question->answer as $key => $dataanswer) {
-            if ($dataanswer != "") {
+            if ($dataanswer != '' || trim($question->feedback[$key])) {
                 $answer = new stdClass;
                 $answer->question = $question->id;
-                $answer->answer   = trim($dataanswer);
+                if (trim($dataanswer) == '') {
+                    $answer->answer = '';
+                } else {
+                    $answer->answer = $this->apply_unit($dataanswer, $units);
+                    if ($answer->answer === false) {
+                        $result->notice = get_string('invalidnumericanswer', 'quiz');
+                    }
+                }
                 $answer->fraction = $question->fraction[$key];
                 $answer->feedback = trim($question->feedback[$key]);
 
@@ -124,7 +133,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
                         $result->error = "Could not update quiz answer! (id=$answer->id)";
                         return $result;
                     }
-                } else {    // This is a completely new answer
+                } else { // This is a completely new answer
                     if (! $answer->id = insert_record("question_answers", $answer)) {
                         $result->error = "Could not insert quiz answer!";
                         return $result;
@@ -137,8 +146,15 @@ class question_numerical_qtype extends question_shortanswer_qtype {
                 }
                 $options->question  = $question->id;
                 $options->answer    = $answer->id;
-                $options->tolerance = $this->apply_unit($question->tolerance[$key], $units);
-
+                if (trim($question->tolerance[$key]) == '') {
+                    $options->tolerance = '';
+                } else {
+                    $options->tolerance = $this->apply_unit($question->tolerance[$key], $units);
+                    if ($options->tolerance === false) {
+                        $result->notice = get_string('invalidnumerictolerance', 'quiz');
+                    }
+                }
+                
                 // Save options
                 if (isset($options->id)) { // reusing existing record
                     if (! update_record('question_numerical', $options)) {
@@ -151,23 +167,28 @@ class question_numerical_qtype extends question_shortanswer_qtype {
                         return $result;
                     }
                 }
+            }
+        }
+        // delete old answer records
+        if (!empty($oldanswers)) {
+            foreach($oldanswers as $oa) {
+                delete_records('question_answers', 'id', $oa->id);
+            }
+        }
 
-                // delete old answer records
-                if (!empty($oldanswers)) {
-                    foreach($oldanswers as $oa) {
-                        delete_records('question_answers', 'id', $oa->id);
-                    }
-                }
-
-                // delete old answer records
-                if (!empty($oldoptions)) {
-                    foreach($oldoptions as $oo) {
-                        delete_records('question_numerical', 'id', $oo->id);
-                    }
-                }
-
+        // delete old answer records
+        if (!empty($oldoptions)) {
+            foreach($oldoptions as $oo) {
+                delete_records('question_numerical', 'id', $oo->id);
             }
         }
+
+        // Report any problems.
+        if (!empty($result->notice)) {
+            return $result;
+        }
+        
+        return true;
     }
 
     function save_numerical_units($question) {
@@ -180,8 +201,8 @@ class question_numerical_qtype extends question_shortanswer_qtype {
         $keys  = array();
         $oldunits = array_values($oldunits);
         usort($oldunits, create_function('$a, $b', // make sure the default unit is at index 0
-         'if (1.0 === (float)$a->multiplier) { return -1; } else '.
-         'if (1.0 === (float)$b->multiplier) { return 1; } else { return 0; }'));
+                'if (1.0 === (float)$a->multiplier) { return -1; } else '.
+                'if (1.0 === (float)$b->multiplier) { return 1; } else { return 0; }'));
         foreach ($oldunits as $unit) {
             $units[] = clone($unit);
         }
@@ -190,8 +211,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
             // Discard any unit which doesn't specify the unit or the multiplier
             if (!empty($question->multiplier[$i]) && !empty($question->unit[$i])) {
                 $units[$i]->question = $question->id;
-                $units[$i]->multiplier =
-                 $this->apply_unit($question->multiplier[$i], array());
+                $units[$i]->multiplier = $this->apply_unit($question->multiplier[$i], array());
                 $units[$i]->unit = $question->unit[$i];
             } else {
                 unset($units[$i]);
@@ -200,6 +220,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
         unset($question->multiplier, $question->unit);
 
         /// Save units
+        $result = new stdClass;
         for ($i = 0; $i < $n; $i++) {
             if (!isset($units[$i]) && isset($oldunits[$i])) { // Delete if it hasn't been resubmitted
                 delete_records('question_numerical_units', 'id', $oldunits[$i]->id);
@@ -223,11 +244,11 @@ class question_numerical_qtype extends question_shortanswer_qtype {
     }
 
     /**
-    * Deletes question from the question-type specific tables
-    *
-    * @return boolean Success/Failure
-    * @param object $question  The question being deleted
-    */
+     * Deletes question from the question-type specific tables
+     *
+     * @return boolean Success/Failure
+     * @param object $question  The question being deleted
+     */
     function delete_question($questionid) {
         delete_records("question_numerical", "question", $questionid);
         delete_records("question_numerical_units", "question", $questionid);
@@ -241,25 +262,25 @@ class question_numerical_qtype extends question_shortanswer_qtype {
         return ($response == $testresponse);
     }
 
-
-
-    // Checks whether a response matches a given answer, taking the tolerance
-    // into account. Returns a true for if a response matches the answer, false
-    // if it doesn't.
+    /**
+     * Checks whether a response matches a given answer, taking the tolerance
+     * and units into account. Returns a true for if a response matches the
+     * answer, false if it doesn't.
+     */
     function test_response(&$question, &$state, $answer) {
-        if (isset($state->responses[''])) {
-            $response = $this->apply_unit(stripslashes($state->responses['']),
-             $question->options->units);
-        } else {
-            $response = '';
+        if ($answer->answer == '') {
+            return true; // Blank answer matches anything.
         }
 
-        if (is_numeric($response) && is_numeric($answer->answer)) {
-            $this->get_tolerance_interval($answer);
-            return ($answer->min <= $response && $answer->max >= $response);
-        } else {
-            return ($response == $answer->answer);
+        $response = $this->apply_unit(stripslashes($state->responses['']), $question->options->units);
+
+        if ($response === false) {
+            return false; // The student did not type a number.
         }
+
+        // The student did type a number, so check it with tolerances.
+        $this->get_tolerance_interval($answer);
+        return ($answer->min <= $response && $response <= $answer->max);
     }
 
     // ULPGC ecastro
@@ -274,18 +295,14 @@ class question_numerical_qtype extends question_shortanswer_qtype {
     }
 
     function grade_responses(&$question, &$state, $cmoptions) {
-        $answers     = &$question->options->answers;
+        $answers = &$question->options->answers;
         $state->raw_grade = 0;
         foreach($answers as $answer) {
             if($this->test_response($question, $state, $answer)) {
-                if ($state->raw_grade < $answer->fraction) {
-                    $state->raw_grade = $answer->fraction;
-                }
+                $state->raw_grade = $answer->fraction;
+                break;
             }
         }
-        if (empty($state->raw_grade)) {
-            $state->raw_grade = 0;
-        }
 
         // Make sure we don't assign negative or too high marks
         $state->raw_grade = min(max((float) $state->raw_grade,
@@ -308,11 +325,12 @@ class question_numerical_qtype extends question_shortanswer_qtype {
 
     // ULPGC ecastro
     function get_all_responses(&$question, &$state) {
-        unset($answers);
+        $result = new stdClass;
+        $answers = array();
         $unit = $this->get_default_numerical_unit($question);
         if (is_array($question->options->answers)) {
             foreach ($question->options->answers as $aid=>$answer) {
-                unset ($r);
+                $r = new stdClass;
                 $r->answer = $answer->answer;
                 $r->credit = $answer->fraction;
                 $this->get_tolerance_interval($answer);
@@ -326,8 +344,6 @@ class question_numerical_qtype extends question_shortanswer_qtype {
                 }
                 $answers[$aid] = $r;
             }
-        } else {
-            $answers[]="error"; // just for debugging, eliminate
         }
         $result->id = $question->id;
         $result->responses = $answers;
@@ -337,8 +353,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
     function get_tolerance_interval(&$answer) {
         // No tolerance
         if (empty($answer->tolerance)) {
-            $answer->min = $answer->max = $answer->answer;
-            return true;
+            $answer->tolerance = 0;
         }
 
         // Calculate the interval of correct responses (min/max)
@@ -376,40 +391,51 @@ class question_numerical_qtype extends question_shortanswer_qtype {
     }
 
     /**
-    * Checks if the $rawresponse has a unit and applys it if appropriate.
-    *
-    * @param string $rawresponse  The response string to be converted to a float.
-    * @param array $units         An array with the defined units, where the
-    *                             unit is the key and the multiplier the value.
-    * @return float               The rawresponse with the unit taken into
-    *                             account as a float.
-    */
+     * Checks if the $rawresponse has a unit and applys it if appropriate.
+     *
+     * @param string $rawresponse  The response string to be converted to a float.
+     * @param array $units         An array with the defined units, where the
+     *                             unit is the key and the multiplier the value.
+     * @return float               The rawresponse with the unit taken into
+     *                             account as a float.
+     */
     function apply_unit($rawresponse, $units) {
         // Make units more useful
         $tmpunits = array();
         foreach ($units as $unit) {
             $tmpunits[$unit->unit] = $unit->multiplier;
         }
-
+        // remove spaces and normalise decimal places.
         $search  = array(' ', ',');
         $replace = array('', '.');
-        $rawresponse = str_replace($search, $replace, $rawresponse); // remove spaces
-        if (ereg(
-         '^([+-]?([0-9]+(\\.[0-9]*)?|[.][0-9]+)([eE][-+]?[0-9]+)?)([^0-9].*)?$',
-         $rawresponse, $responseparts)) {
-            $responsenum  = (float)$responseparts[1];
-            if (isset($tmpunits[$responseparts[5]])) {
-                return (float)$responseparts[1] / $tmpunits[$responseparts[5]];
+        $rawresponse = str_replace($search, $replace, trim($rawresponse));
+        
+        // Apply any unit that is present.
+        if (ereg('^([+-]?([0-9]+(\\.[0-9]*)?|\\.[0-9]+)([eE][-+]?[0-9]+)?)([^0-9].*)?$',
+                $rawresponse, $responseparts)) {
+                    
+            if (!empty($responseparts[5])) {
+                
+                if (isset($tmpunits[$responseparts[5]])) {
+                    // Valid number with unit.
+                    return (float)$responseparts[1] / $tmpunits[$responseparts[5]];
+                } else {
+                    // Valid number with invalid unit. Must be wrong.
+                    return false;
+                }
+
             } else {
+                // Valid number without unit.
                 return (float)$responseparts[1];
             }
         }
-        return $rawresponse;
+        // Invalid number. Must be wrong.
+        return false;
     }
     
-/// BACKUP FUNCTIONS ////////////////////////////
+    /// BACKUP FUNCTIONS ////////////////////////////
 
-    /*
+    /**
      * Backup the data in the question
      *
      * This is used in question/backuplib.php
@@ -437,9 +463,9 @@ class question_numerical_qtype extends question_shortanswer_qtype {
         return $status;
     }
 
-/// RESTORE FUNCTIONS /////////////////
+    /// RESTORE FUNCTIONS /////////////////
 
-    /*
+    /**
      * Restores the data in the question
      *
      * This is used in question/restorelib.php
@@ -456,6 +482,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
             $num_info = $numericals[$i];
 
             //Now, build the question_numerical record structure
+            $numerical = new stdClass;
             $numerical->question = $new_question_id;
             $numerical->answer = backup_todb($num_info['#']['ANSWER']['0']['#']);
             $numerical->tolerance = backup_todb($num_info['#']['TOLERANCE']['0']['#']);
@@ -467,7 +494,7 @@ class question_numerical_qtype extends question_shortanswer_qtype {
             }
 
             //The structure is equal to the db, so insert the question_numerical
-            $newid = insert_record ("question_numerical",$numerical);
+            $newid = insert_record ("question_numerical", $numerical);
 
             //Do some output
             if (($i+1) % 50 == 0) {
@@ -492,11 +519,8 @@ class question_numerical_qtype extends question_shortanswer_qtype {
     }
 
 }
-//// END OF CLASS ////
 
-//////////////////////////////////////////////////////////////////////////
-//// INITIATION - Without this line the question type is not in use... ///
-//////////////////////////////////////////////////////////////////////////
+// INITIATION - Without this line the question type is not in use.
 $QTYPES['numerical']= new question_numerical_qtype();
 // The following adds the questiontype to the menu of types shown to teachers
 $QTYPE_MENU['numerical'] = get_string("numerical", "quiz");