<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://docs.moodle.org/dev/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Ppichet</id>
	<title>MoodleDocs - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://docs.moodle.org/dev/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Ppichet"/>
	<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/Special:Contributions/Ppichet"/>
	<updated>2026-06-07T04:12:46Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Calculated_question_:_adding_new_math_functions&amp;diff=47016</id>
		<title>Calculated question : adding new math functions</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Calculated_question_:_adding_new_math_functions&amp;diff=47016"/>
		<updated>2014-12-12T23:43:57Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: /* Available functions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The calculated question type could benefit of the EvalMath module to increase the math functions useable in the Calculated, Simple calculated et Multiple choice calculated question types.&lt;br /&gt;
==Available functions==&lt;br /&gt;
&lt;br /&gt;
Calculated questions can use more than simple arithmetic operators. &lt;br /&gt;
The following functions are allowed in versions 1.5 and newer.&lt;br /&gt;
In 2,9 we should continue to support the previous functions unless they can be unsafe.&lt;br /&gt;
All functions will use either the EvalMath code or a more specific CalculatedEvalMath code.&lt;br /&gt;
In the following table &lt;br /&gt;
to be improved as ... there is some ambiguity on  columns names (&lt;br /&gt;
  # means that the function exists. &lt;br /&gt;
  new means that the function needs to be created in EvalMath or only in  CalculatedEvalMath. (... to be explained more clearly )&lt;br /&gt;
   OK  will be used in test column to confirm that this property has been coded and testing code have been added in  2.9&lt;br /&gt;
   NO i.e. no more supported in 2,9&lt;br /&gt;
{| width=&amp;quot;97%&amp;quot; border=&amp;quot;1px&amp;quot;&lt;br /&gt;
!Function&lt;br /&gt;
!1,5+&lt;br /&gt;
!Math&lt;br /&gt;
lib&lt;br /&gt;
!Eval&lt;br /&gt;
Math&lt;br /&gt;
!Calc&lt;br /&gt;
!coded&lt;br /&gt;
!tested&lt;br /&gt;
!Explanation&lt;br /&gt;
|-&lt;br /&gt;
|abs&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Absolute value&lt;br /&gt;
|-&lt;br /&gt;
|acos&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Arc cosine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|acosh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Inverse hyperbolic cosine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|asin&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Arc sine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|asinh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Inverse hyperbolic sine.-- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|atan2&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Arc tangent of two variables -- pass in two values like (y, x), and you&#039;ll get the atan(y/x), adjusted to the proper quadrant. (Note: The variables are in the reverse order to atan2(x,y) in Excel) Output is radians.&lt;br /&gt;
|-&lt;br /&gt;
|atan&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Arc tangent -- output in radians.   &lt;br /&gt;
|-&lt;br /&gt;
|atanh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Inverse hyperbolic tangent-- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|bindec&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Binary to decimal&lt;br /&gt;
|-&lt;br /&gt;
|ceil&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Round fractions up&lt;br /&gt;
|-&lt;br /&gt;
|cos&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Cosine -- in radians!!!  Convert your degree measurement to radians before you take the cos of it.&lt;br /&gt;
|-&lt;br /&gt;
|cosh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Hyperbolic cosine -- in radians!!!  Convert your degree measurement to radians before you take the cosh of it.&lt;br /&gt;
|-&lt;br /&gt;
|decbin&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Decimal to binary&lt;br /&gt;
|-&lt;br /&gt;
|decoct&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Decimal to octal&lt;br /&gt;
|-&lt;br /&gt;
|deg2rad&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Converts the number in degrees to the radian equivalent&lt;br /&gt;
|-&lt;br /&gt;
|exp&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Calculates the exponent of e&lt;br /&gt;
|-&lt;br /&gt;
|expm1&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Returns exp(number) - 1, computed in a way that is accurate even when the value of number is close to zero&lt;br /&gt;
|-&lt;br /&gt;
|floor&lt;br /&gt;
|&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Round fractions down&lt;br /&gt;
|-&lt;br /&gt;
|fmod&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Returns the floating-point modulus of two numbers - i.e. the remainder when the first is divided by the second.&lt;br /&gt;
|-&lt;br /&gt;
|is_finite&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Finds whether a value is a legal finite number&lt;br /&gt;
|-&lt;br /&gt;
|is_infinite&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|??&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Finds whether a value is infinite&lt;br /&gt;
|-&lt;br /&gt;
|is_nan&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|??&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Finds whether a value is not a number&lt;br /&gt;
|-&lt;br /&gt;
|log10&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Base-10 logarithm&lt;br /&gt;
|-&lt;br /&gt;
|log1p&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Returns log(1 + number), computed in a way that is accurate even when the value of number is close to zero&lt;br /&gt;
|-&lt;br /&gt;
|log&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Natural logarithm (&#039;&#039;ln&#039;&#039;)&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|max&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Find highest value&lt;br /&gt;
|-&lt;br /&gt;
|min&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Find lowest value&lt;br /&gt;
|-&lt;br /&gt;
|octdec&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Octal to decimal&lt;br /&gt;
|-&lt;br /&gt;
|pi()&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Get value of pi - the function does not take an argument, like in Excel.&lt;br /&gt;
|-&lt;br /&gt;
|pow (numberToRaise, NumberRaisedTo)&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|new &lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|power (numberToRaise, NumberRaisedTo)&lt;br /&gt;
|&lt;br /&gt;
| # &lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Exponential expression&lt;br /&gt;
|-&lt;br /&gt;
|rad2deg&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Converts the radian number to the equivalent number in degrees&lt;br /&gt;
|-&lt;br /&gt;
|rand&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Generate a random integer&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
|rand_int&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Generate a random integer&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
|rand_float&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Generate a random float&lt;br /&gt;
|-&lt;br /&gt;
|round&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Rounds a float&lt;br /&gt;
|-&lt;br /&gt;
|sin&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Sine -- in radians!!!  Convert your degree measurement to radians before you take the sin of it.&lt;br /&gt;
|-&lt;br /&gt;
|sinh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Hyperbolic sine -- in radians!!!  Convert your degree measurement to radians before you take the sinh of it.&lt;br /&gt;
|-&lt;br /&gt;
|sqrt&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Square root&lt;br /&gt;
|-&lt;br /&gt;
|tan&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Tangent -- in radians!!!  Convert your degree measurement to radians before you take the tan of it.&lt;br /&gt;
|-&lt;br /&gt;
|tanh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Hyperbolic tangent -- in radians!!!  Convert your degree measurement to radians before you take the tanh of it.&lt;br /&gt;
|}&lt;br /&gt;
to be completed --[[User:Pierre Pichet|Pierre Pichet]] ([[User talk:Pierre Pichet|talk]]) 12:12, 12 December 2014 (AWST)&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Calculated_question_:_adding_new_math_functions&amp;diff=47015</id>
		<title>Calculated question : adding new math functions</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Calculated_question_:_adding_new_math_functions&amp;diff=47015"/>
		<updated>2014-12-12T18:30:06Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: /* Available functions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The calculated question type could benefit of the EvalMath module to increase the math functions useable in the Calculated, Simple calculated et Multiple choice calculated question types.&lt;br /&gt;
==Available functions==&lt;br /&gt;
&lt;br /&gt;
Calculated questions can use more than simple arithmetic operators. &lt;br /&gt;
The following functions are allowed in versions 1.5 and newer.&lt;br /&gt;
In 2,9 we should continue to support the previous functions unless they can be unsafe.&lt;br /&gt;
All functions will use either the EvalMath code or a more specific CalculatedEvalMath code.&lt;br /&gt;
In the following table &lt;br /&gt;
to be improved as ... there is some ambiguity on  columns names (&lt;br /&gt;
  # means that the function exists. &lt;br /&gt;
  new means that the function needs to be created in EvalMath or only in  CalculatedEvalMath. (... to be explained more clearly )&lt;br /&gt;
   OK  will be used in test column to confirm that this property has been coded and testing code have been added in  2.9&lt;br /&gt;
   NO i.e. no more supported in 2,9&lt;br /&gt;
{| width=&amp;quot;97%&amp;quot; border=&amp;quot;1px&amp;quot;&lt;br /&gt;
!Function&lt;br /&gt;
!1,5+&lt;br /&gt;
!Math&lt;br /&gt;
lib&lt;br /&gt;
!Eval&lt;br /&gt;
Math&lt;br /&gt;
!Calc&lt;br /&gt;
!coded&lt;br /&gt;
!tested&lt;br /&gt;
!Explanation&lt;br /&gt;
|-&lt;br /&gt;
|abs&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Absolute value&lt;br /&gt;
|-&lt;br /&gt;
|acos&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Arc cosine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|acosh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Inverse hyperbolic cosine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|asin&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Arc sine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|asinh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Inverse hyperbolic sine.-- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|atan2&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Arc tangent of two variables -- pass in two values like (y, x), and you&#039;ll get the atan(y/x), adjusted to the proper quadrant. (Note: The variables are in the reverse order to atan2(x,y) in Excel) Output is radians.&lt;br /&gt;
|-&lt;br /&gt;
|atan&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Arc tangent -- output in radians.   &lt;br /&gt;
|-&lt;br /&gt;
|atanh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Inverse hyperbolic tangent-- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|bindec&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Binary to decimal&lt;br /&gt;
|-&lt;br /&gt;
|ceil&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Round fractions up&lt;br /&gt;
|-&lt;br /&gt;
|cos&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Cosine -- in radians!!!  Convert your degree measurement to radians before you take the cos of it.&lt;br /&gt;
|-&lt;br /&gt;
|cosh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Hyperbolic cosine -- in radians!!!  Convert your degree measurement to radians before you take the cosh of it.&lt;br /&gt;
|-&lt;br /&gt;
|decbin&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Decimal to binary&lt;br /&gt;
|-&lt;br /&gt;
|decoct&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Decimal to octal&lt;br /&gt;
|-&lt;br /&gt;
|deg2rad&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Converts the number in degrees to the radian equivalent&lt;br /&gt;
|-&lt;br /&gt;
|exp&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Calculates the exponent of e&lt;br /&gt;
|-&lt;br /&gt;
|expm1&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Returns exp(number) - 1, computed in a way that is accurate even when the value of number is close to zero&lt;br /&gt;
|-&lt;br /&gt;
|floor&lt;br /&gt;
|&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Round fractions down&lt;br /&gt;
|-&lt;br /&gt;
|fmod&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Returns the floating-point modulus of two numbers - i.e. the remainder when the first is divided by the second.&lt;br /&gt;
|-&lt;br /&gt;
|is_finite&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Finds whether a value is a legal finite number&lt;br /&gt;
|-&lt;br /&gt;
|is_infinite&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|??&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Finds whether a value is infinite&lt;br /&gt;
|-&lt;br /&gt;
|is_nan&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|??&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Finds whether a value is not a number&lt;br /&gt;
|-&lt;br /&gt;
|log10&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Base-10 logarithm&lt;br /&gt;
|-&lt;br /&gt;
|log1p&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Returns log(1 + number), computed in a way that is accurate even when the value of number is close to zero&lt;br /&gt;
|-&lt;br /&gt;
|log&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Natural logarithm (&#039;&#039;ln&#039;&#039;)&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|max&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Find highest value&lt;br /&gt;
|-&lt;br /&gt;
|min&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Find lowest value&lt;br /&gt;
|-&lt;br /&gt;
|octdec&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Octal to decimal&lt;br /&gt;
|-&lt;br /&gt;
|pi()&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Get value of pi - the function does not take an argument, like in Excel.&lt;br /&gt;
|-&lt;br /&gt;
|pow (numberToRaise, NumberRaisedTo)&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|new &lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|power (numberToRaise, NumberRaisedTo)&lt;br /&gt;
|&lt;br /&gt;
| # &lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Exponential expression&lt;br /&gt;
|-&lt;br /&gt;
|rad2deg&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Converts the radian number to the equivalent number in degrees&lt;br /&gt;
|-&lt;br /&gt;
|rand&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Generate a random integer&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
|rand_int&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Generate a random integer&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
|rand_float&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Generate a random float&lt;br /&gt;
|-&lt;br /&gt;
|round&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Rounds a float&lt;br /&gt;
|-&lt;br /&gt;
|sin&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Sine -- in radians!!!  Convert your degree measurement to radians before you take the sin of it.&lt;br /&gt;
|-&lt;br /&gt;
|sinh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Hyperbolic sine -- in radians!!!  Convert your degree measurement to radians before you take the sinh of it.&lt;br /&gt;
|-&lt;br /&gt;
|sqrt&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Square root&lt;br /&gt;
|-&lt;br /&gt;
|tan&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Tangent -- in radians!!!  Convert your degree measurement to radians before you take the tan of it.&lt;br /&gt;
|-&lt;br /&gt;
|tanh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Hyperbolic tangent -- in radians!!!  Convert your degree measurement to radians before you take the tanh of it.&lt;br /&gt;
|}&lt;br /&gt;
to be completed --[[User:Pierre Pichet|Pierre Pichet]] ([[User talk:Pierre Pichet|talk]]) 12:12, 12 December 2014 (AWST)&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Calculated_question_:_adding_new_math_functions&amp;diff=47014</id>
		<title>Calculated question : adding new math functions</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Calculated_question_:_adding_new_math_functions&amp;diff=47014"/>
		<updated>2014-12-12T17:41:28Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: /* Available functions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The calculated question type could benefit of the EvalMath module to increase the math functions useable in the Calculated, Simple calculated et Multiple choice calculated question types.&lt;br /&gt;
==Available functions==&lt;br /&gt;
&lt;br /&gt;
Calculated questions can use more than simple arithmetic operators. &lt;br /&gt;
The following functions are allowed in versions 1.5 and newer.&lt;br /&gt;
In 2,9 we should continue to support the previous functions unless they can be unsafe.&lt;br /&gt;
All functions will use either the EvalMath code or a more specific CalculatedEvalMath code.&lt;br /&gt;
In the following table &lt;br /&gt;
to be improved as ... there is some ambiguity on  columns names (&lt;br /&gt;
  # means that the function exists. &lt;br /&gt;
  new means that the function needs to be created in EvalMath or only in  CalculatedEvalMath. (... to be explained more clearly )&lt;br /&gt;
   OK  will be used in test column to confirm that this property has been coded and testing code have been added in  2.9&lt;br /&gt;
   NO i.e. no more supported in 2,9&lt;br /&gt;
{| width=&amp;quot;97%&amp;quot; border=&amp;quot;1px&amp;quot;&lt;br /&gt;
!Function&lt;br /&gt;
!1,5+&lt;br /&gt;
!Eval&lt;br /&gt;
Math&lt;br /&gt;
!Calc&lt;br /&gt;
!coded&lt;br /&gt;
!tested&lt;br /&gt;
!Explanation&lt;br /&gt;
|-&lt;br /&gt;
|abs&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Absolute value&lt;br /&gt;
|-&lt;br /&gt;
|acos&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Arc cosine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|acosh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Inverse hyperbolic cosine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|asin&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Arc sine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|asinh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Inverse hyperbolic sine.-- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|atan2&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Arc tangent of two variables -- pass in two values like (y, x), and you&#039;ll get the atan(y/x), adjusted to the proper quadrant. (Note: The variables are in the reverse order to atan2(x,y) in Excel) Output is radians.&lt;br /&gt;
|-&lt;br /&gt;
|atan&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Arc tangent -- output in radians.   &lt;br /&gt;
|-&lt;br /&gt;
|atanh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Inverse hyperbolic tangent-- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|bindec&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Binary to decimal&lt;br /&gt;
|-&lt;br /&gt;
|ceil&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Round fractions up&lt;br /&gt;
|-&lt;br /&gt;
|cos&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Cosine -- in radians!!!  Convert your degree measurement to radians before you take the cos of it.&lt;br /&gt;
|-&lt;br /&gt;
|cosh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Hyperbolic cosine -- in radians!!!  Convert your degree measurement to radians before you take the cosh of it.&lt;br /&gt;
|-&lt;br /&gt;
|decbin&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Decimal to binary&lt;br /&gt;
|-&lt;br /&gt;
|decoct&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Decimal to octal&lt;br /&gt;
|-&lt;br /&gt;
|deg2rad&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Converts the number in degrees to the radian equivalent&lt;br /&gt;
|-&lt;br /&gt;
|exp&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Calculates the exponent of e&lt;br /&gt;
|-&lt;br /&gt;
|expm1&lt;br /&gt;
|&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Returns exp(number) - 1, computed in a way that is accurate even when the value of number is close to zero&lt;br /&gt;
|-&lt;br /&gt;
|floor&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Round fractions down&lt;br /&gt;
|-&lt;br /&gt;
|fmod&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Returns the floating-point modulus of two numbers - i.e. the remainder when the first is divided by the second.&lt;br /&gt;
|-&lt;br /&gt;
|is_finite&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Finds whether a value is a legal finite number&lt;br /&gt;
|-&lt;br /&gt;
|is_infinite&lt;br /&gt;
| #&lt;br /&gt;
|??&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Finds whether a value is infinite&lt;br /&gt;
|-&lt;br /&gt;
|is_nan&lt;br /&gt;
| #&lt;br /&gt;
|??&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Finds whether a value is not a number&lt;br /&gt;
|-&lt;br /&gt;
|log10&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Base-10 logarithm&lt;br /&gt;
|-&lt;br /&gt;
|log1p&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Returns log(1 + number), computed in a way that is accurate even when the value of number is close to zero&lt;br /&gt;
|-&lt;br /&gt;
|log&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Natural logarithm (&#039;&#039;ln&#039;&#039;)&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|max&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Find highest value&lt;br /&gt;
|-&lt;br /&gt;
|min&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Find lowest value&lt;br /&gt;
|-&lt;br /&gt;
|octdec&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Octal to decimal&lt;br /&gt;
|-&lt;br /&gt;
|pi()&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Get value of pi - the function does not take an argument, like in Excel.&lt;br /&gt;
|-&lt;br /&gt;
|pow (numberToRaise, NumberRaisedTo)&lt;br /&gt;
| #&lt;br /&gt;
|new &lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|power (numberToRaise, NumberRaisedTo)&lt;br /&gt;
|&lt;br /&gt;
| # &lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Exponential expression&lt;br /&gt;
|-&lt;br /&gt;
|rad2deg&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Converts the radian number to the equivalent number in degrees&lt;br /&gt;
|-&lt;br /&gt;
|rand&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Generate a random integer&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
|rand_int&lt;br /&gt;
|&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Generate a random integer&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
|rand_float&lt;br /&gt;
|&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Generate a random float&lt;br /&gt;
|-&lt;br /&gt;
|round&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Rounds a float&lt;br /&gt;
|-&lt;br /&gt;
|sin&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Sine -- in radians!!!  Convert your degree measurement to radians before you take the sin of it.&lt;br /&gt;
|-&lt;br /&gt;
|sinh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Hyperbolic sine -- in radians!!!  Convert your degree measurement to radians before you take the sinh of it.&lt;br /&gt;
|-&lt;br /&gt;
|sqrt&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Square root&lt;br /&gt;
|-&lt;br /&gt;
|tan&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Tangent -- in radians!!!  Convert your degree measurement to radians before you take the tan of it.&lt;br /&gt;
|-&lt;br /&gt;
|tanh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Hyperbolic tangent -- in radians!!!  Convert your degree measurement to radians before you take the tanh of it.&lt;br /&gt;
|}&lt;br /&gt;
to be completed --[[User:Pierre Pichet|Pierre Pichet]] ([[User talk:Pierre Pichet|talk]]) 12:12, 12 December 2014 (AWST)&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Calculated_question_:_adding_new_math_functions&amp;diff=47013</id>
		<title>Calculated question : adding new math functions</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Calculated_question_:_adding_new_math_functions&amp;diff=47013"/>
		<updated>2014-12-12T17:02:39Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: /* Available functions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The calculated question type could benefit of the EvalMath module to increase the math functions useable in the Calculated, Simple calculated et Multiple choice calculated question types.&lt;br /&gt;
==Available functions==&lt;br /&gt;
&lt;br /&gt;
Calculated questions can use more than simple arithmetic operators. &lt;br /&gt;
The following functions are allowed in versions 1.5 and newer.&lt;br /&gt;
In 2,9 we should continue to support the previous functions unless they can be unsafe.&lt;br /&gt;
All functions will use either the EvalMath code or a more specific CalculatedEvalMath code.&lt;br /&gt;
In the following table &lt;br /&gt;
  # means that the function exists. &lt;br /&gt;
  new means that the function needs to be created in EvalMath or only in  CalculatedEvalMath. &lt;br /&gt;
   OK  will be used in test column to confirm that this property has been coded and testing code have been added in  2.9&lt;br /&gt;
   NO i.e. no more supported in 2,9&lt;br /&gt;
{| width=&amp;quot;97%&amp;quot; border=&amp;quot;1px&amp;quot;&lt;br /&gt;
!Function&lt;br /&gt;
!1,5+&lt;br /&gt;
!Eval&lt;br /&gt;
Math&lt;br /&gt;
!Calc&lt;br /&gt;
!coded&lt;br /&gt;
!tested&lt;br /&gt;
!Explanation&lt;br /&gt;
|-&lt;br /&gt;
|abs&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Absolute value&lt;br /&gt;
|-&lt;br /&gt;
|acos&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Arc cosine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|acosh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Inverse hyperbolic cosine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|asin&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Arc sine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|asinh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Inverse hyperbolic sine.-- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|atan2&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Arc tangent of two variables -- pass in two values like (y, x), and you&#039;ll get the atan(y/x), adjusted to the proper quadrant. (Note: The variables are in the reverse order to atan2(x,y) in Excel) Output is radians.&lt;br /&gt;
|-&lt;br /&gt;
|atan&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Arc tangent -- output in radians.   &lt;br /&gt;
|-&lt;br /&gt;
|atanh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Inverse hyperbolic tangent-- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|bindec&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Binary to decimal&lt;br /&gt;
|-&lt;br /&gt;
|ceil&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Round fractions up&lt;br /&gt;
|-&lt;br /&gt;
|cos&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Cosine -- in radians!!!  Convert your degree measurement to radians before you take the cos of it.&lt;br /&gt;
|-&lt;br /&gt;
|cosh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Hyperbolic cosine -- in radians!!!  Convert your degree measurement to radians before you take the cosh of it.&lt;br /&gt;
|-&lt;br /&gt;
|decbin&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Decimal to binary&lt;br /&gt;
|-&lt;br /&gt;
|decoct&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Decimal to octal&lt;br /&gt;
|-&lt;br /&gt;
|deg2rad&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Converts the number in degrees to the radian equivalent&lt;br /&gt;
|-&lt;br /&gt;
|exp&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Calculates the exponent of e&lt;br /&gt;
|-&lt;br /&gt;
|expm1&lt;br /&gt;
|&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Returns exp(number) - 1, computed in a way that is accurate even when the value of number is close to zero&lt;br /&gt;
|-&lt;br /&gt;
|floor&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Round fractions down&lt;br /&gt;
|-&lt;br /&gt;
|fmod&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Returns the floating-point modulus of two numbers - i.e. the remainder when the first is divided by the second.&lt;br /&gt;
|-&lt;br /&gt;
|is_finite&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Finds whether a value is a legal finite number&lt;br /&gt;
|-&lt;br /&gt;
|is_infinite&lt;br /&gt;
| #&lt;br /&gt;
|??&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Finds whether a value is infinite&lt;br /&gt;
|-&lt;br /&gt;
|is_nan&lt;br /&gt;
| #&lt;br /&gt;
|??&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Finds whether a value is not a number&lt;br /&gt;
|-&lt;br /&gt;
|log10&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Base-10 logarithm&lt;br /&gt;
|-&lt;br /&gt;
|log1p&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Returns log(1 + number), computed in a way that is accurate even when the value of number is close to zero&lt;br /&gt;
|-&lt;br /&gt;
|log&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Natural logarithm (&#039;&#039;ln&#039;&#039;)&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|max&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Find highest value&lt;br /&gt;
|-&lt;br /&gt;
|min&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Find lowest value&lt;br /&gt;
|-&lt;br /&gt;
|octdec&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Octal to decimal&lt;br /&gt;
|-&lt;br /&gt;
|pi()&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Get value of pi - the function does not take an argument, like in Excel.&lt;br /&gt;
|-&lt;br /&gt;
|pow (numberToRaise, NumberRaisedTo)&lt;br /&gt;
| #&lt;br /&gt;
|new &lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|power (numberToRaise, NumberRaisedTo)&lt;br /&gt;
|&lt;br /&gt;
| # &lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|Exponential expression&lt;br /&gt;
|-&lt;br /&gt;
|rad2deg&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Converts the radian number to the equivalent number in degrees&lt;br /&gt;
|-&lt;br /&gt;
|rand&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Generate a random integer&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
|rand_int&lt;br /&gt;
|&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|Generate a random integer&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
|rand_float&lt;br /&gt;
|&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|Generate a random float&lt;br /&gt;
|-&lt;br /&gt;
|round&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Rounds a float&lt;br /&gt;
|-&lt;br /&gt;
|sin&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Sine -- in radians!!!  Convert your degree measurement to radians before you take the sin of it.&lt;br /&gt;
|-&lt;br /&gt;
|sinh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Hyperbolic sine -- in radians!!!  Convert your degree measurement to radians before you take the sinh of it.&lt;br /&gt;
|-&lt;br /&gt;
|sqrt&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Square root&lt;br /&gt;
|-&lt;br /&gt;
|tan&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Tangent -- in radians!!!  Convert your degree measurement to radians before you take the tan of it.&lt;br /&gt;
|-&lt;br /&gt;
|tanh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Hyperbolic tangent -- in radians!!!  Convert your degree measurement to radians before you take the tanh of it.&lt;br /&gt;
|}&lt;br /&gt;
to be completed --[[User:Pierre Pichet|Pierre Pichet]] ([[User talk:Pierre Pichet|talk]]) 12:12, 12 December 2014 (AWST)&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Calculated_question_:_adding_new_math_functions&amp;diff=47012</id>
		<title>Calculated question : adding new math functions</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Calculated_question_:_adding_new_math_functions&amp;diff=47012"/>
		<updated>2014-12-12T16:56:23Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: /* Available functions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The calculated question type could benefit of the EvalMath module to increase the math functions useable in the Calculated, Simple calculated et Multiple choice calculated question types.&lt;br /&gt;
==Available functions==&lt;br /&gt;
&lt;br /&gt;
Calculated questions can use more than simple arithmetic operators. &lt;br /&gt;
The following functions are allowed in versions 1.5 and newer.&lt;br /&gt;
In 2,9 we should continue to support the previous functions unless they can be unsafe.&lt;br /&gt;
All functions will use either the EvalMath code or a more specific CalculatedEvalMath code.&lt;br /&gt;
In the following table &lt;br /&gt;
  # means that the function exists. &lt;br /&gt;
  new means that the function needs to be created in EvalMath or only in  CalculatedEvalMath. &lt;br /&gt;
   OK  will be used in test column to confirm that this property has been coded and testing code have been added in  2.9&lt;br /&gt;
   NO i.e. no more supported in 2,9&lt;br /&gt;
{| width=&amp;quot;97%&amp;quot; border=&amp;quot;1px&amp;quot;&lt;br /&gt;
!Function&lt;br /&gt;
!1,5+&lt;br /&gt;
!Eval&lt;br /&gt;
Math&lt;br /&gt;
!Calc&lt;br /&gt;
!tested&lt;br /&gt;
!Explanation&lt;br /&gt;
|-&lt;br /&gt;
|abs&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Absolute value&lt;br /&gt;
|-&lt;br /&gt;
|acos&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Arc cosine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|acosh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Inverse hyperbolic cosine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|asin&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Arc sine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|asinh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Inverse hyperbolic sine.-- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|atan2&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Arc tangent of two variables -- pass in two values like (y, x), and you&#039;ll get the atan(y/x), adjusted to the proper quadrant. (Note: The variables are in the reverse order to atan2(x,y) in Excel) Output is radians.&lt;br /&gt;
|-&lt;br /&gt;
|atan&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Arc tangent -- output in radians.   &lt;br /&gt;
|-&lt;br /&gt;
|atanh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Inverse hyperbolic tangent-- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|bindec&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Binary to decimal&lt;br /&gt;
|-&lt;br /&gt;
|ceil&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Round fractions up&lt;br /&gt;
|-&lt;br /&gt;
|cos&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Cosine -- in radians!!!  Convert your degree measurement to radians before you take the cos of it.&lt;br /&gt;
|-&lt;br /&gt;
|cosh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Hyperbolic cosine -- in radians!!!  Convert your degree measurement to radians before you take the cosh of it.&lt;br /&gt;
|-&lt;br /&gt;
|decbin&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Decimal to binary&lt;br /&gt;
|-&lt;br /&gt;
|decoct&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Decimal to octal&lt;br /&gt;
|-&lt;br /&gt;
|deg2rad&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Converts the number in degrees to the radian equivalent&lt;br /&gt;
|-&lt;br /&gt;
|exp&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Calculates the exponent of e&lt;br /&gt;
|-&lt;br /&gt;
|expm1&lt;br /&gt;
|&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Returns exp(number) - 1, computed in a way that is accurate even when the value of number is close to zero&lt;br /&gt;
|-&lt;br /&gt;
|floor&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Round fractions down&lt;br /&gt;
|-&lt;br /&gt;
|fmod&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Returns the floating-point modulus of two numbers - i.e. the remainder when the first is divided by the second.&lt;br /&gt;
|-&lt;br /&gt;
|is_finite&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Finds whether a value is a legal finite number&lt;br /&gt;
|-&lt;br /&gt;
|is_infinite&lt;br /&gt;
| #&lt;br /&gt;
|??&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Finds whether a value is infinite&lt;br /&gt;
|-&lt;br /&gt;
|is_nan&lt;br /&gt;
| #&lt;br /&gt;
|??&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Finds whether a value is not a number&lt;br /&gt;
|-&lt;br /&gt;
|log10&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Base-10 logarithm&lt;br /&gt;
|-&lt;br /&gt;
|log1p&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Returns log(1 + number), computed in a way that is accurate even when the value of number is close to zero&lt;br /&gt;
|-&lt;br /&gt;
|log&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Natural logarithm (&#039;&#039;ln&#039;&#039;)&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|max&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Find highest value&lt;br /&gt;
|-&lt;br /&gt;
|min&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Find lowest value&lt;br /&gt;
|-&lt;br /&gt;
|octdec&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Octal to decimal&lt;br /&gt;
|-&lt;br /&gt;
|pi()&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Get value of pi - the function does not take an argument, like in Excel.&lt;br /&gt;
|-&lt;br /&gt;
|pow (numberToRaise, NumberRaisedTo)&lt;br /&gt;
| #&lt;br /&gt;
|new &lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|power (numberToRaise, NumberRaisedTo)&lt;br /&gt;
|&lt;br /&gt;
| # &lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|Exponential expression&lt;br /&gt;
|-&lt;br /&gt;
|rad2deg&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Converts the radian number to the equivalent number in degrees&lt;br /&gt;
|-&lt;br /&gt;
|rand&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Generate a random integer&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
|rand_int&lt;br /&gt;
|&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|Generate a random integer&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
|rand_float&lt;br /&gt;
|&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|Generate a random float&lt;br /&gt;
|-&lt;br /&gt;
|round&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Rounds a float&lt;br /&gt;
|-&lt;br /&gt;
|sin&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Sine -- in radians!!!  Convert your degree measurement to radians before you take the sin of it.&lt;br /&gt;
|-&lt;br /&gt;
|sinh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Hyperbolic sine -- in radians!!!  Convert your degree measurement to radians before you take the sinh of it.&lt;br /&gt;
|-&lt;br /&gt;
|sqrt&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Square root&lt;br /&gt;
|-&lt;br /&gt;
|tan&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Tangent -- in radians!!!  Convert your degree measurement to radians before you take the tan of it.&lt;br /&gt;
|-&lt;br /&gt;
|tanh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Hyperbolic tangent -- in radians!!!  Convert your degree measurement to radians before you take the tanh of it.&lt;br /&gt;
|}&lt;br /&gt;
to be completed --[[User:Pierre Pichet|Pierre Pichet]] ([[User talk:Pierre Pichet|talk]]) 12:12, 12 December 2014 (AWST)&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Calculated_question_:_adding_new_math_functions&amp;diff=47011</id>
		<title>Calculated question : adding new math functions</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Calculated_question_:_adding_new_math_functions&amp;diff=47011"/>
		<updated>2014-12-12T16:43:47Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: /* Available functions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The calculated question type could benefit of the EvalMath module to increase the math functions useable in the Calculated, Simple calculated et Multiple choice calculated question types.&lt;br /&gt;
==Available functions==&lt;br /&gt;
&lt;br /&gt;
Calculated questions can use more than simple arithmetic operators. The following functions are allowed in versions 1.5 and newer.&lt;br /&gt;
In the following table &lt;br /&gt;
  # means that the function exists. &lt;br /&gt;
  new means that the function needs to be created in EvalMath or only in Calculated questiontype.. &lt;br /&gt;
   OK  will be used in test column to confirm that this property has been coded and testing code have been added in  2.9&lt;br /&gt;
{| width=&amp;quot;97%&amp;quot; border=&amp;quot;1px&amp;quot;&lt;br /&gt;
!Function&lt;br /&gt;
!1,5+&lt;br /&gt;
!Eval&lt;br /&gt;
Math&lt;br /&gt;
!Calc&lt;br /&gt;
!tested&lt;br /&gt;
!Explanation&lt;br /&gt;
|-&lt;br /&gt;
|abs&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Absolute value&lt;br /&gt;
|-&lt;br /&gt;
|acos&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Arc cosine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|acosh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Inverse hyperbolic cosine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|asin&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Arc sine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|asinh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Inverse hyperbolic sine.-- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|atan2&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Arc tangent of two variables -- pass in two values like (y, x), and you&#039;ll get the atan(y/x), adjusted to the proper quadrant. (Note: The variables are in the reverse order to atan2(x,y) in Excel) Output is radians.&lt;br /&gt;
|-&lt;br /&gt;
|atan&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Arc tangent -- output in radians.   &lt;br /&gt;
|-&lt;br /&gt;
|atanh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Inverse hyperbolic tangent-- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|bindec&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Binary to decimal&lt;br /&gt;
|-&lt;br /&gt;
|ceil&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Round fractions up&lt;br /&gt;
|-&lt;br /&gt;
|cos&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Cosine -- in radians!!!  Convert your degree measurement to radians before you take the cos of it.&lt;br /&gt;
|-&lt;br /&gt;
|cosh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Hyperbolic cosine -- in radians!!!  Convert your degree measurement to radians before you take the cosh of it.&lt;br /&gt;
|-&lt;br /&gt;
|decbin&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Decimal to binary&lt;br /&gt;
|-&lt;br /&gt;
|decoct&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Decimal to octal&lt;br /&gt;
|-&lt;br /&gt;
|deg2rad&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Converts the number in degrees to the radian equivalent&lt;br /&gt;
|-&lt;br /&gt;
|exp&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Calculates the exponent of e&lt;br /&gt;
|-&lt;br /&gt;
|expm1&lt;br /&gt;
|&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Returns exp(number) - 1, computed in a way that is accurate even when the value of number is close to zero&lt;br /&gt;
|-&lt;br /&gt;
|floor&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Round fractions down&lt;br /&gt;
|-&lt;br /&gt;
|fmod&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Returns the floating-point modulus of two numbers - i.e. the remainder when the first is divided by the second.&lt;br /&gt;
|-&lt;br /&gt;
|is_finite&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Finds whether a value is a legal finite number&lt;br /&gt;
|-&lt;br /&gt;
|is_infinite&lt;br /&gt;
| #&lt;br /&gt;
|??&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Finds whether a value is infinite&lt;br /&gt;
|-&lt;br /&gt;
|is_nan&lt;br /&gt;
| #&lt;br /&gt;
|??&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Finds whether a value is not a number&lt;br /&gt;
|-&lt;br /&gt;
|log10&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Base-10 logarithm&lt;br /&gt;
|-&lt;br /&gt;
|log1p&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Returns log(1 + number), computed in a way that is accurate even when the value of number is close to zero&lt;br /&gt;
|-&lt;br /&gt;
|log&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Natural logarithm (&#039;&#039;ln&#039;&#039;)&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|max&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Find highest value&lt;br /&gt;
|-&lt;br /&gt;
|min&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Find lowest value&lt;br /&gt;
|-&lt;br /&gt;
|octdec&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Octal to decimal&lt;br /&gt;
|-&lt;br /&gt;
|pi()&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Get value of pi - the function does not take an argument, like in Excel.&lt;br /&gt;
|-&lt;br /&gt;
|pow (numberToRaise, NumberRaisedTo)&lt;br /&gt;
| #&lt;br /&gt;
|new &lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|power (numberToRaise, NumberRaisedTo)&lt;br /&gt;
|&lt;br /&gt;
| # &lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|Exponential expression&lt;br /&gt;
|-&lt;br /&gt;
|rad2deg&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Converts the radian number to the equivalent number in degrees&lt;br /&gt;
|-&lt;br /&gt;
|rand&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Generate a random integer&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
|rand_int&lt;br /&gt;
|&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|Generate a random integer&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
|rand_float&lt;br /&gt;
|&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|Generate a random float&lt;br /&gt;
|-&lt;br /&gt;
|round&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Rounds a float&lt;br /&gt;
|-&lt;br /&gt;
|sin&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Sine -- in radians!!!  Convert your degree measurement to radians before you take the sin of it.&lt;br /&gt;
|-&lt;br /&gt;
|sinh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Hyperbolic sine -- in radians!!!  Convert your degree measurement to radians before you take the sinh of it.&lt;br /&gt;
|-&lt;br /&gt;
|sqrt&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Square root&lt;br /&gt;
|-&lt;br /&gt;
|tan&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Tangent -- in radians!!!  Convert your degree measurement to radians before you take the tan of it.&lt;br /&gt;
|-&lt;br /&gt;
|tanh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Hyperbolic tangent -- in radians!!!  Convert your degree measurement to radians before you take the tanh of it.&lt;br /&gt;
|}&lt;br /&gt;
to be completed --[[User:Pierre Pichet|Pierre Pichet]] ([[User talk:Pierre Pichet|talk]]) 12:12, 12 December 2014 (AWST)&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Calculated_question_:_adding_new_math_functions&amp;diff=47010</id>
		<title>Calculated question : adding new math functions</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Calculated_question_:_adding_new_math_functions&amp;diff=47010"/>
		<updated>2014-12-12T16:36:11Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: /* Available functions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The calculated question type could benefit of the EvalMath module to increase the math functions useable in the Calculated, Simple calculated et Multiple choice calculated question types.&lt;br /&gt;
==Available functions==&lt;br /&gt;
&lt;br /&gt;
Calculated questions can use more than simple arithmetic operators. The following functions are allowed in versions 1.5 and newer.&lt;br /&gt;
In the following table &lt;br /&gt;
  # means that the function exists. &lt;br /&gt;
  new means that the function needs to be created in EvalMath or only in Calculated questiontype.. &lt;br /&gt;
   OK  will be used in test column to confirm that this property has been coded and testing code have been added in  2.9&lt;br /&gt;
{| width=&amp;quot;97%&amp;quot; border=&amp;quot;1px&amp;quot;&lt;br /&gt;
!Function&lt;br /&gt;
!1,5+&lt;br /&gt;
!Eval&lt;br /&gt;
Math&lt;br /&gt;
!2.9&lt;br /&gt;
!tested&lt;br /&gt;
!Explanation&lt;br /&gt;
|-&lt;br /&gt;
|abs&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Absolute value&lt;br /&gt;
|-&lt;br /&gt;
|acos&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Arc cosine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|acosh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Inverse hyperbolic cosine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|asin&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Arc sine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|asinh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Inverse hyperbolic sine.-- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|atan2&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Arc tangent of two variables -- pass in two values like (y, x), and you&#039;ll get the atan(y/x), adjusted to the proper quadrant. (Note: The variables are in the reverse order to atan2(x,y) in Excel) Output is radians.&lt;br /&gt;
|-&lt;br /&gt;
|atan&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Arc tangent -- output in radians.   &lt;br /&gt;
|-&lt;br /&gt;
|atanh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Inverse hyperbolic tangent-- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|bindec&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Binary to decimal&lt;br /&gt;
|-&lt;br /&gt;
|ceil&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Round fractions up&lt;br /&gt;
|-&lt;br /&gt;
|cos&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Cosine -- in radians!!!  Convert your degree measurement to radians before you take the cos of it.&lt;br /&gt;
|-&lt;br /&gt;
|cosh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Hyperbolic cosine -- in radians!!!  Convert your degree measurement to radians before you take the cosh of it.&lt;br /&gt;
|-&lt;br /&gt;
|decbin&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Decimal to binary&lt;br /&gt;
|-&lt;br /&gt;
|decoct&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Decimal to octal&lt;br /&gt;
|-&lt;br /&gt;
|deg2rad&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Converts the number in degrees to the radian equivalent&lt;br /&gt;
|-&lt;br /&gt;
|exp&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Calculates the exponent of e&lt;br /&gt;
|-&lt;br /&gt;
|expm1&lt;br /&gt;
|&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Returns exp(number) - 1, computed in a way that is accurate even when the value of number is close to zero&lt;br /&gt;
|-&lt;br /&gt;
|floor&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Round fractions down&lt;br /&gt;
|-&lt;br /&gt;
|fmod&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Returns the floating-point modulus of two numbers - i.e. the remainder when the first is divided by the second.&lt;br /&gt;
|-&lt;br /&gt;
|is_finite&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Finds whether a value is a legal finite number&lt;br /&gt;
|-&lt;br /&gt;
|is_infinite&lt;br /&gt;
| #&lt;br /&gt;
|??&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Finds whether a value is infinite&lt;br /&gt;
|-&lt;br /&gt;
|is_nan&lt;br /&gt;
| #&lt;br /&gt;
|??&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Finds whether a value is not a number&lt;br /&gt;
|-&lt;br /&gt;
|log10&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Base-10 logarithm&lt;br /&gt;
|-&lt;br /&gt;
|log1p&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Returns log(1 + number), computed in a way that is accurate even when the value of number is close to zero&lt;br /&gt;
|-&lt;br /&gt;
|log&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Natural logarithm (&#039;&#039;ln&#039;&#039;)&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|max&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Find highest value&lt;br /&gt;
|-&lt;br /&gt;
|min&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Find lowest value&lt;br /&gt;
|-&lt;br /&gt;
|octdec&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Octal to decimal&lt;br /&gt;
|-&lt;br /&gt;
|pi()&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Get value of pi - the function does not take an argument, like in Excel.&lt;br /&gt;
|-&lt;br /&gt;
|pow (numberToRaise, NumberRaisedTo)&lt;br /&gt;
| #&lt;br /&gt;
|new &lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|power (numberToRaise, NumberRaisedTo)&lt;br /&gt;
|&lt;br /&gt;
| # &lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|Exponential expression&lt;br /&gt;
|-&lt;br /&gt;
|rad2deg&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Converts the radian number to the equivalent number in degrees&lt;br /&gt;
|-&lt;br /&gt;
|rand&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Generate a random integer&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
|rand_int&lt;br /&gt;
|&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|Generate a random integer&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
|rand_float&lt;br /&gt;
|&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|Generate a random float&lt;br /&gt;
|-&lt;br /&gt;
|round&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Rounds a float&lt;br /&gt;
|-&lt;br /&gt;
|sin&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Sine -- in radians!!!  Convert your degree measurement to radians before you take the sin of it.&lt;br /&gt;
|-&lt;br /&gt;
|sinh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Hyperbolic sine -- in radians!!!  Convert your degree measurement to radians before you take the sinh of it.&lt;br /&gt;
|-&lt;br /&gt;
|sqrt&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Square root&lt;br /&gt;
|-&lt;br /&gt;
|tan&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Tangent -- in radians!!!  Convert your degree measurement to radians before you take the tan of it.&lt;br /&gt;
|-&lt;br /&gt;
|tanh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Hyperbolic tangent -- in radians!!!  Convert your degree measurement to radians before you take the tanh of it.&lt;br /&gt;
|}&lt;br /&gt;
to be completed --[[User:Pierre Pichet|Pierre Pichet]] ([[User talk:Pierre Pichet|talk]]) 12:12, 12 December 2014 (AWST)&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Calculated_question_:_adding_new_math_functions&amp;diff=47009</id>
		<title>Calculated question : adding new math functions</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Calculated_question_:_adding_new_math_functions&amp;diff=47009"/>
		<updated>2014-12-12T16:28:07Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The calculated question type could benefit of the EvalMath module to increase the math functions useable in the Calculated, Simple calculated et Multiple choice calculated question types.&lt;br /&gt;
==Available functions==&lt;br /&gt;
&lt;br /&gt;
Calculated questions can use more than simple arithmetic operators. The following functions are allowed in versions 1.5 and newer.&lt;br /&gt;
In the following table &lt;br /&gt;
  # means that the function exists, if it exists in EvalMath then it should exist in 2,9. &lt;br /&gt;
  new means that the function needs to be created in EvalMath or only in Calculated questiontype.. &lt;br /&gt;
   OK  will be used in test column to confirm that this property is set to 2.9&lt;br /&gt;
{| width=&amp;quot;97%&amp;quot; border=&amp;quot;1px&amp;quot;&lt;br /&gt;
!Function&lt;br /&gt;
!1,5+&lt;br /&gt;
!Eval&lt;br /&gt;
Math&lt;br /&gt;
!2.9&lt;br /&gt;
!tested&lt;br /&gt;
!Explanation&lt;br /&gt;
|-&lt;br /&gt;
|abs&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Absolute value&lt;br /&gt;
|-&lt;br /&gt;
|acos&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Arc cosine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|acosh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Inverse hyperbolic cosine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|asin&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Arc sine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|asinh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Inverse hyperbolic sine.-- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|atan2&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Arc tangent of two variables -- pass in two values like (y, x), and you&#039;ll get the atan(y/x), adjusted to the proper quadrant. (Note: The variables are in the reverse order to atan2(x,y) in Excel) Output is radians.&lt;br /&gt;
|-&lt;br /&gt;
|atan&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Arc tangent -- output in radians.   &lt;br /&gt;
|-&lt;br /&gt;
|atanh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Inverse hyperbolic tangent-- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|bindec&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Binary to decimal&lt;br /&gt;
|-&lt;br /&gt;
|ceil&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Round fractions up&lt;br /&gt;
|-&lt;br /&gt;
|cos&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Cosine -- in radians!!!  Convert your degree measurement to radians before you take the cos of it.&lt;br /&gt;
|-&lt;br /&gt;
|cosh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Hyperbolic cosine -- in radians!!!  Convert your degree measurement to radians before you take the cosh of it.&lt;br /&gt;
|-&lt;br /&gt;
|decbin&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Decimal to binary&lt;br /&gt;
|-&lt;br /&gt;
|decoct&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Decimal to octal&lt;br /&gt;
|-&lt;br /&gt;
|deg2rad&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Converts the number in degrees to the radian equivalent&lt;br /&gt;
|-&lt;br /&gt;
|exp&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Calculates the exponent of e&lt;br /&gt;
|-&lt;br /&gt;
|expm1&lt;br /&gt;
|&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Returns exp(number) - 1, computed in a way that is accurate even when the value of number is close to zero&lt;br /&gt;
|-&lt;br /&gt;
|floor&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Round fractions down&lt;br /&gt;
|-&lt;br /&gt;
|fmod&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Returns the floating-point modulus of two numbers - i.e. the remainder when the first is divided by the second.&lt;br /&gt;
|-&lt;br /&gt;
|is_finite&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Finds whether a value is a legal finite number&lt;br /&gt;
|-&lt;br /&gt;
|is_infinite&lt;br /&gt;
| #&lt;br /&gt;
|??&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Finds whether a value is infinite&lt;br /&gt;
|-&lt;br /&gt;
|is_nan&lt;br /&gt;
| #&lt;br /&gt;
|??&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Finds whether a value is not a number&lt;br /&gt;
|-&lt;br /&gt;
|log10&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Base-10 logarithm&lt;br /&gt;
|-&lt;br /&gt;
|log1p&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Returns log(1 + number), computed in a way that is accurate even when the value of number is close to zero&lt;br /&gt;
|-&lt;br /&gt;
|log&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Natural logarithm (&#039;&#039;ln&#039;&#039;)&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|max&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Find highest value&lt;br /&gt;
|-&lt;br /&gt;
|min&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Find lowest value&lt;br /&gt;
|-&lt;br /&gt;
|octdec&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Octal to decimal&lt;br /&gt;
|-&lt;br /&gt;
|pi()&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Get value of pi - the function does not take an argument, like in Excel.&lt;br /&gt;
|-&lt;br /&gt;
|pow (numberToRaise, NumberRaisedTo)&lt;br /&gt;
| #&lt;br /&gt;
|new &lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|power (numberToRaise, NumberRaisedTo)&lt;br /&gt;
|&lt;br /&gt;
| # &lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|Exponential expression&lt;br /&gt;
|-&lt;br /&gt;
|rad2deg&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Converts the radian number to the equivalent number in degrees&lt;br /&gt;
|-&lt;br /&gt;
|rand&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Generate a random integer&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
|rand_int&lt;br /&gt;
|&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|Generate a random integer&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
|rand_float&lt;br /&gt;
|&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|Generate a random float&lt;br /&gt;
|-&lt;br /&gt;
|round&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Rounds a float&lt;br /&gt;
|-&lt;br /&gt;
|sin&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Sine -- in radians!!!  Convert your degree measurement to radians before you take the sin of it.&lt;br /&gt;
|-&lt;br /&gt;
|sinh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Hyperbolic sine -- in radians!!!  Convert your degree measurement to radians before you take the sinh of it.&lt;br /&gt;
|-&lt;br /&gt;
|sqrt&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Square root&lt;br /&gt;
|-&lt;br /&gt;
|tan&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Tangent -- in radians!!!  Convert your degree measurement to radians before you take the tan of it.&lt;br /&gt;
|-&lt;br /&gt;
|tanh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Hyperbolic tangent -- in radians!!!  Convert your degree measurement to radians before you take the tanh of it.&lt;br /&gt;
|}&lt;br /&gt;
to be completed --[[User:Pierre Pichet|Pierre Pichet]] ([[User talk:Pierre Pichet|talk]]) 12:12, 12 December 2014 (AWST)&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Calculated_question_:_adding_new_math_functions&amp;diff=47008</id>
		<title>Calculated question : adding new math functions</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Calculated_question_:_adding_new_math_functions&amp;diff=47008"/>
		<updated>2014-12-12T04:12:08Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: /* Available functions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The calculated question type could benefit of the EvalMath module to increase the math functions useable in the Calculated, Simple calculated et Multiple choice calculated question types.&lt;br /&gt;
==Available functions==&lt;br /&gt;
&lt;br /&gt;
Calculated questions can use more than simple arithmetic operators. The following functions are allowed in versions 1.5 and newer.&lt;br /&gt;
In the following table &lt;br /&gt;
  # means that the function exists, if it exists in EvalMath then it should exist in 2,9. &lt;br /&gt;
  new means that the function needs to be created in EvalMath. &lt;br /&gt;
   OK  will be used in test column to confirm that this property is set to 2.9&lt;br /&gt;
{| width=&amp;quot;97%&amp;quot; border=&amp;quot;1px&amp;quot;&lt;br /&gt;
!Function&lt;br /&gt;
!1,5+&lt;br /&gt;
!Eval&lt;br /&gt;
Math&lt;br /&gt;
!2.9&lt;br /&gt;
!tested&lt;br /&gt;
!Explanation&lt;br /&gt;
|-&lt;br /&gt;
|abs&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Absolute value&lt;br /&gt;
|-&lt;br /&gt;
|acos&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Arc cosine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|acosh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Inverse hyperbolic cosine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|asin&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Arc sine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|asinh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Inverse hyperbolic sine.-- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|atan2&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Arc tangent of two variables -- pass in two values like (y, x), and you&#039;ll get the atan(y/x), adjusted to the proper quadrant. (Note: The variables are in the reverse order to atan2(x,y) in Excel) Output is radians.&lt;br /&gt;
|-&lt;br /&gt;
|atan&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Arc tangent -- output in radians.   &lt;br /&gt;
|-&lt;br /&gt;
|atanh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Inverse hyperbolic tangent-- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|bindec&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Binary to decimal&lt;br /&gt;
|-&lt;br /&gt;
|ceil&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Round fractions up&lt;br /&gt;
|-&lt;br /&gt;
|cos&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Cosine -- in radians!!!  Convert your degree measurement to radians before you take the cos of it.&lt;br /&gt;
|-&lt;br /&gt;
|cosh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Hyperbolic cosine -- in radians!!!  Convert your degree measurement to radians before you take the cosh of it.&lt;br /&gt;
|-&lt;br /&gt;
|decbin&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Decimal to binary&lt;br /&gt;
|-&lt;br /&gt;
|decoct&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Decimal to octal&lt;br /&gt;
|-&lt;br /&gt;
|deg2rad&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Converts the number in degrees to the radian equivalent&lt;br /&gt;
|-&lt;br /&gt;
|exp&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Calculates the exponent of e&lt;br /&gt;
|-&lt;br /&gt;
|expm1&lt;br /&gt;
|&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Returns exp(number) - 1, computed in a way that is accurate even when the value of number is close to zero&lt;br /&gt;
|-&lt;br /&gt;
|floor&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Round fractions down&lt;br /&gt;
|-&lt;br /&gt;
|fmod&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Returns the floating-point modulus of two numbers - i.e. the remainder when the first is divided by the second.&lt;br /&gt;
|-&lt;br /&gt;
|is_finite&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Finds whether a value is a legal finite number&lt;br /&gt;
|-&lt;br /&gt;
|is_infinite&lt;br /&gt;
| #&lt;br /&gt;
|??&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Finds whether a value is infinite&lt;br /&gt;
|-&lt;br /&gt;
|is_nan&lt;br /&gt;
| #&lt;br /&gt;
|??&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Finds whether a value is not a number&lt;br /&gt;
|-&lt;br /&gt;
|log10&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Base-10 logarithm&lt;br /&gt;
|-&lt;br /&gt;
|log1p&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Returns log(1 + number), computed in a way that is accurate even when the value of number is close to zero&lt;br /&gt;
|-&lt;br /&gt;
|log&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Natural logarithm (&#039;&#039;ln&#039;&#039;)&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|max&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Find highest value&lt;br /&gt;
|-&lt;br /&gt;
|min&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Find lowest value&lt;br /&gt;
|-&lt;br /&gt;
|octdec&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Octal to decimal&lt;br /&gt;
|-&lt;br /&gt;
|pi()&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Get value of pi - the function does not take an argument, like in Excel.&lt;br /&gt;
|-&lt;br /&gt;
|pow (numberToRaise, NumberRaisedTo)&lt;br /&gt;
| #&lt;br /&gt;
|new &lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|power (numberToRaise, NumberRaisedTo)&lt;br /&gt;
|&lt;br /&gt;
| # &lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|Exponential expression&lt;br /&gt;
|-&lt;br /&gt;
|rad2deg&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Converts the radian number to the equivalent number in degrees&lt;br /&gt;
|-&lt;br /&gt;
|rand&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Generate a random integer&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
|rand_int&lt;br /&gt;
|&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|Generate a random integer&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
|rand_float&lt;br /&gt;
|&lt;br /&gt;
| #&lt;br /&gt;
|new&lt;br /&gt;
|&lt;br /&gt;
|Generate a random float&lt;br /&gt;
|-&lt;br /&gt;
|round&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Rounds a float&lt;br /&gt;
|-&lt;br /&gt;
|sin&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Sine -- in radians!!!  Convert your degree measurement to radians before you take the sin of it.&lt;br /&gt;
|-&lt;br /&gt;
|sinh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Hyperbolic sine -- in radians!!!  Convert your degree measurement to radians before you take the sinh of it.&lt;br /&gt;
|-&lt;br /&gt;
|sqrt&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Square root&lt;br /&gt;
|-&lt;br /&gt;
|tan&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Tangent -- in radians!!!  Convert your degree measurement to radians before you take the tan of it.&lt;br /&gt;
|-&lt;br /&gt;
|tanh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Hyperbolic tangent -- in radians!!!  Convert your degree measurement to radians before you take the tanh of it.&lt;br /&gt;
|}&lt;br /&gt;
to be completed --[[User:Pierre Pichet|Pierre Pichet]] ([[User talk:Pierre Pichet|talk]]) 12:12, 12 December 2014 (AWST)&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Calculated_question_:_adding_new_math_functions&amp;diff=47007</id>
		<title>Calculated question : adding new math functions</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Calculated_question_:_adding_new_math_functions&amp;diff=47007"/>
		<updated>2014-12-12T03:39:11Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: /* Available functions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The calculated question type could benefit of the EvalMath module to increase the math functions useable in the Calculated, Simple calculated et Multiple choice calculated question types.&lt;br /&gt;
==Available functions==&lt;br /&gt;
&lt;br /&gt;
Calculated questions can use more than simple arithmetic operators. The following functions are allowed in versions 1.5 and newer.&lt;br /&gt;
&lt;br /&gt;
{| width=&amp;quot;97%&amp;quot; border=&amp;quot;1px&amp;quot;&lt;br /&gt;
!Function&lt;br /&gt;
!1,5+&lt;br /&gt;
!Eval&lt;br /&gt;
Math&lt;br /&gt;
!2.9&lt;br /&gt;
!tested&lt;br /&gt;
!Explanation&lt;br /&gt;
|-&lt;br /&gt;
|abs&lt;br /&gt;
|  &#039;&#039;&#039;*&#039;&#039;&#039;&lt;br /&gt;
|  &#039;&#039;&#039;*&#039;&#039;&#039;&lt;br /&gt;
|  &#039;&#039;&#039;*&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|Absolute value&lt;br /&gt;
|-&lt;br /&gt;
|acos&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Arc cosine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|acosh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&#039;&lt;br /&gt;
|&lt;br /&gt;
|Inverse hyperbolic cosine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|asin&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Arc sine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|asinh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Inverse hyperbolic sine.-- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|atan2&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Arc tangent of two variables -- pass in two values like (y, x), and you&#039;ll get the atan(y/x), adjusted to the proper quadrant. (Note: The variables are in the reverse order to atan2(x,y) in Excel) Output is radians.&lt;br /&gt;
|-&lt;br /&gt;
|atan&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Arc tangent -- output in radians.   &lt;br /&gt;
|-&lt;br /&gt;
|atanh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Inverse hyperbolic tangent-- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|bindec&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Binary to decimal&lt;br /&gt;
|-&lt;br /&gt;
|ceil&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Round fractions up&lt;br /&gt;
|-&lt;br /&gt;
|cos&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Cosine -- in radians!!!  Convert your degree measurement to radians before you take the cos of it.&lt;br /&gt;
|-&lt;br /&gt;
|cosh&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Hyperbolic cosine -- in radians!!!  Convert your degree measurement to radians before you take the cosh of it.&lt;br /&gt;
|-&lt;br /&gt;
|decbin&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Decimal to binary&lt;br /&gt;
|-&lt;br /&gt;
|decoct&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Decimal to octal&lt;br /&gt;
|-&lt;br /&gt;
|deg2rad&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Converts the number in degrees to the radian equivalent&lt;br /&gt;
|-&lt;br /&gt;
|exp&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Calculates the exponent of e&lt;br /&gt;
|-&lt;br /&gt;
|expm1&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Returns exp(number) - 1, computed in a way that is accurate even when the value of number is close to zero&lt;br /&gt;
|-&lt;br /&gt;
|floor&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Round fractions down&lt;br /&gt;
|-&lt;br /&gt;
|fmod&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Returns the floating-point modulus of two numbers - i.e. the remainder when the first is divided by the second.&lt;br /&gt;
|-&lt;br /&gt;
|is_finite&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Finds whether a value is a legal finite number&lt;br /&gt;
|-&lt;br /&gt;
|is_infinite&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Finds whether a value is infinite&lt;br /&gt;
|-&lt;br /&gt;
|is_nan&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Finds whether a value is not a number&lt;br /&gt;
|-&lt;br /&gt;
|log10&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Base-10 logarithm&lt;br /&gt;
|-&lt;br /&gt;
|log1p&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Returns log(1 + number), computed in a way that is accurate even when the value of number is close to zero&lt;br /&gt;
|-&lt;br /&gt;
|log&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Natural logarithm (&#039;&#039;ln&#039;&#039;)&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|max&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Find highest value&lt;br /&gt;
|-&lt;br /&gt;
|min&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Find lowest value&lt;br /&gt;
|-&lt;br /&gt;
|octdec&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Octal to decimal&lt;br /&gt;
|-&lt;br /&gt;
|pi()&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
| #&lt;br /&gt;
|&lt;br /&gt;
|Get value of pi - the function does not take an argument, like in Excel.&lt;br /&gt;
|-&lt;br /&gt;
|pow (numberToRaise, NumberRaisedTo)&lt;br /&gt;
| #&lt;br /&gt;
| &lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Exponential expression&lt;br /&gt;
|-&lt;br /&gt;
|rad2deg&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Converts the radian number to the equivalent number in degrees&lt;br /&gt;
|-&lt;br /&gt;
|rand&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Generate a random integer&lt;br /&gt;
|-&lt;br /&gt;
|round&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Rounds a float&lt;br /&gt;
|-&lt;br /&gt;
|sin&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Sine -- in radians!!!  Convert your degree measurement to radians before you take the sin of it.&lt;br /&gt;
|-&lt;br /&gt;
|sinh&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Hyperbolic sine -- in radians!!!  Convert your degree measurement to radians before you take the sinh of it.&lt;br /&gt;
|-&lt;br /&gt;
|sqrt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Square root&lt;br /&gt;
|-&lt;br /&gt;
|tan&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Tangent -- in radians!!!  Convert your degree measurement to radians before you take the tan of it.&lt;br /&gt;
|-&lt;br /&gt;
|tanh&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Hyperbolic tangent -- in radians!!!  Convert your degree measurement to radians before you take the tanh of it.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Calculated_question_:_adding_new_math_functions&amp;diff=47006</id>
		<title>Calculated question : adding new math functions</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Calculated_question_:_adding_new_math_functions&amp;diff=47006"/>
		<updated>2014-12-12T03:14:51Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The calculated question type could benefit of the EvalMath module to increase the math functions useable in the Calculated, Simple calculated et Multiple choice calculated question types.&lt;br /&gt;
==Available functions==&lt;br /&gt;
&lt;br /&gt;
Calculated questions can use more than simple arithmetic operators. The following functions are allowed in versions 1.5 and newer.&lt;br /&gt;
&lt;br /&gt;
{| width=&amp;quot;97%&amp;quot; border=&amp;quot;1px&amp;quot;&lt;br /&gt;
!Function&lt;br /&gt;
!1,5+&lt;br /&gt;
!Eval&lt;br /&gt;
Math&lt;br /&gt;
!2.9&lt;br /&gt;
!tested&lt;br /&gt;
!Explanation&lt;br /&gt;
|-&lt;br /&gt;
|abs&lt;br /&gt;
|  &#039;&#039;&#039;*&#039;&#039;&#039;&lt;br /&gt;
|  &#039;&#039;&#039;*&#039;&#039;&#039;&lt;br /&gt;
|  &#039;&#039;&#039;*&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|Absolute value&lt;br /&gt;
|-&lt;br /&gt;
|acos&lt;br /&gt;
|  &#039;&#039;&#039;*&#039;&#039;&#039;&lt;br /&gt;
|  &#039;&#039;&#039;*&#039;&#039;&#039;&lt;br /&gt;
|  &#039;&#039;&#039;*&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|Arc cosine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|acosh&lt;br /&gt;
|  &#039;&#039;&#039;*&#039;&#039;&lt;br /&gt;
|  &#039;&#039;&#039;*&#039;&#039;&#039;&lt;br /&gt;
|  &#039;&#039;&#039;*&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|Inverse hyperbolic cosine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|asin&lt;br /&gt;
|  &#039;&#039;&#039;*&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Arc sine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|asinh&lt;br /&gt;
|  &#039;&#039;&#039;*&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Inverse hyperbolic sine.-- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|atan2&lt;br /&gt;
|  &#039;&#039;&#039;*&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Arc tangent of two variables -- pass in two values like (y, x), and you&#039;ll get the atan(y/x), adjusted to the proper quadrant. (Note: The variables are in the reverse order to atan2(x,y) in Excel) Output is radians.&lt;br /&gt;
|-&lt;br /&gt;
|atan&lt;br /&gt;
|  &#039;&#039;&#039;*&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Arc tangent -- output in radians.   &lt;br /&gt;
|-&lt;br /&gt;
|atanh&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Inverse hyperbolic tangent-- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|bindec&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Binary to decimal&lt;br /&gt;
|-&lt;br /&gt;
|ceil&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Round fractions up&lt;br /&gt;
|-&lt;br /&gt;
|cos&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Cosine -- in radians!!!  Convert your degree measurement to radians before you take the cos of it.&lt;br /&gt;
|-&lt;br /&gt;
|cosh&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Hyperbolic cosine -- in radians!!!  Convert your degree measurement to radians before you take the cosh of it.&lt;br /&gt;
|-&lt;br /&gt;
|decbin&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Decimal to binary&lt;br /&gt;
|-&lt;br /&gt;
|decoct&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Decimal to octal&lt;br /&gt;
|-&lt;br /&gt;
|deg2rad&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Converts the number in degrees to the radian equivalent&lt;br /&gt;
|-&lt;br /&gt;
|exp&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Calculates the exponent of e&lt;br /&gt;
|-&lt;br /&gt;
|expm1&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Returns exp(number) - 1, computed in a way that is accurate even when the value of number is close to zero&lt;br /&gt;
|-&lt;br /&gt;
|floor&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Round fractions down&lt;br /&gt;
|-&lt;br /&gt;
|fmod&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Returns the floating-point modulus of two numbers - i.e. the remainder when the first is divided by the second.&lt;br /&gt;
|-&lt;br /&gt;
|is_finite&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Finds whether a value is a legal finite number&lt;br /&gt;
|-&lt;br /&gt;
|is_infinite&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Finds whether a value is infinite&lt;br /&gt;
|-&lt;br /&gt;
|is_nan&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Finds whether a value is not a number&lt;br /&gt;
|-&lt;br /&gt;
|log10&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Base-10 logarithm&lt;br /&gt;
|-&lt;br /&gt;
|log1p&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Returns log(1 + number), computed in a way that is accurate even when the value of number is close to zero&lt;br /&gt;
|-&lt;br /&gt;
|log&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Natural logarithm (&#039;&#039;ln&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
|max&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Find highest value&lt;br /&gt;
|-&lt;br /&gt;
|min&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Find lowest value&lt;br /&gt;
|-&lt;br /&gt;
|octdec&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Octal to decimal&lt;br /&gt;
|-&lt;br /&gt;
|pi()&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Get value of pi - the function does not take an argument, like in Excel.&lt;br /&gt;
|-&lt;br /&gt;
|pow (numberToRaise, NumberRaisedTo)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Exponential expression&lt;br /&gt;
|-&lt;br /&gt;
|rad2deg&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Converts the radian number to the equivalent number in degrees&lt;br /&gt;
|-&lt;br /&gt;
|rand&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Generate a random integer&lt;br /&gt;
|-&lt;br /&gt;
|round&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Rounds a float&lt;br /&gt;
|-&lt;br /&gt;
|sin&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Sine -- in radians!!!  Convert your degree measurement to radians before you take the sin of it.&lt;br /&gt;
|-&lt;br /&gt;
|sinh&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Hyperbolic sine -- in radians!!!  Convert your degree measurement to radians before you take the sinh of it.&lt;br /&gt;
|-&lt;br /&gt;
|sqrt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Square root&lt;br /&gt;
|-&lt;br /&gt;
|tan&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Tangent -- in radians!!!  Convert your degree measurement to radians before you take the tan of it.&lt;br /&gt;
|-&lt;br /&gt;
|tanh&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Hyperbolic tangent -- in radians!!!  Convert your degree measurement to radians before you take the tanh of it.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Calculated_question_:_adding_new_math_functions&amp;diff=47005</id>
		<title>Calculated question : adding new math functions</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Calculated_question_:_adding_new_math_functions&amp;diff=47005"/>
		<updated>2014-12-12T02:54:20Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: /* Available functions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The calculated question type could benefit of the EvalMath module to increase the math functions useable in the Calculated, Simple calculated et Multiple choice calculated question types.&lt;br /&gt;
==Available functions==&lt;br /&gt;
&lt;br /&gt;
Calculated questions can use more than simple arithmetic operators. The following functions are allowed in versions 1.5 and newer.&lt;br /&gt;
&lt;br /&gt;
{| width=&amp;quot;97%&amp;quot; border=&amp;quot;1px&amp;quot;&lt;br /&gt;
!Function&lt;br /&gt;
!1,5+&lt;br /&gt;
!Eval&lt;br /&gt;
Math&lt;br /&gt;
!2.9&lt;br /&gt;
!tested&lt;br /&gt;
!Explanation&lt;br /&gt;
|-&lt;br /&gt;
|abs&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Absolute value&lt;br /&gt;
|-&lt;br /&gt;
|acos&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Arc cosine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|acosh&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Inverse hyperbolic cosine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|asin&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Arc sine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|asinh&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Inverse hyperbolic sine.-- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|atan2&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Arc tangent of two variables -- pass in two values like (y, x), and you&#039;ll get the atan(y/x), adjusted to the proper quadrant. (Note: The variables are in the reverse order to atan2(x,y) in Excel) Output is radians.&lt;br /&gt;
|-&lt;br /&gt;
|atan&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Arc tangent -- output in radians.   &lt;br /&gt;
|-&lt;br /&gt;
|atanh&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Inverse hyperbolic tangent-- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|bindec&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Binary to decimal&lt;br /&gt;
|-&lt;br /&gt;
|ceil&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Round fractions up&lt;br /&gt;
|-&lt;br /&gt;
|cos&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Cosine -- in radians!!!  Convert your degree measurement to radians before you take the cos of it.&lt;br /&gt;
|-&lt;br /&gt;
|cosh&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Hyperbolic cosine -- in radians!!!  Convert your degree measurement to radians before you take the cosh of it.&lt;br /&gt;
|-&lt;br /&gt;
|decbin&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Decimal to binary&lt;br /&gt;
|-&lt;br /&gt;
|decoct&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Decimal to octal&lt;br /&gt;
|-&lt;br /&gt;
|deg2rad&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Converts the number in degrees to the radian equivalent&lt;br /&gt;
|-&lt;br /&gt;
|exp&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Calculates the exponent of e&lt;br /&gt;
|-&lt;br /&gt;
|expm1&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Returns exp(number) - 1, computed in a way that is accurate even when the value of number is close to zero&lt;br /&gt;
|-&lt;br /&gt;
|floor&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Round fractions down&lt;br /&gt;
|-&lt;br /&gt;
|fmod&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Returns the floating-point modulus of two numbers - i.e. the remainder when the first is divided by the second.&lt;br /&gt;
|-&lt;br /&gt;
|is_finite&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Finds whether a value is a legal finite number&lt;br /&gt;
|-&lt;br /&gt;
|is_infinite&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Finds whether a value is infinite&lt;br /&gt;
|-&lt;br /&gt;
|is_nan&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Finds whether a value is not a number&lt;br /&gt;
|-&lt;br /&gt;
|log10&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Base-10 logarithm&lt;br /&gt;
|-&lt;br /&gt;
|log1p&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Returns log(1 + number), computed in a way that is accurate even when the value of number is close to zero&lt;br /&gt;
|-&lt;br /&gt;
|log&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Natural logarithm (&#039;&#039;ln&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
|max&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Find highest value&lt;br /&gt;
|-&lt;br /&gt;
|min&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Find lowest value&lt;br /&gt;
|-&lt;br /&gt;
|octdec&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Octal to decimal&lt;br /&gt;
|-&lt;br /&gt;
|pi()&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Get value of pi - the function does not take an argument, like in Excel.&lt;br /&gt;
|-&lt;br /&gt;
|pow (numberToRaise, NumberRaisedTo)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Exponential expression&lt;br /&gt;
|-&lt;br /&gt;
|rad2deg&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Converts the radian number to the equivalent number in degrees&lt;br /&gt;
|-&lt;br /&gt;
|rand&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Generate a random integer&lt;br /&gt;
|-&lt;br /&gt;
|round&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Rounds a float&lt;br /&gt;
|-&lt;br /&gt;
|sin&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Sine -- in radians!!!  Convert your degree measurement to radians before you take the sin of it.&lt;br /&gt;
|-&lt;br /&gt;
|sinh&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Hyperbolic sine -- in radians!!!  Convert your degree measurement to radians before you take the sinh of it.&lt;br /&gt;
|-&lt;br /&gt;
|sqrt&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Square root&lt;br /&gt;
|-&lt;br /&gt;
|tan&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Tangent -- in radians!!!  Convert your degree measurement to radians before you take the tan of it.&lt;br /&gt;
|-&lt;br /&gt;
|tanh&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Hyperbolic tangent -- in radians!!!  Convert your degree measurement to radians before you take the tanh of it.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Calculated_question_:_adding_new_math_functions&amp;diff=47004</id>
		<title>Calculated question : adding new math functions</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Calculated_question_:_adding_new_math_functions&amp;diff=47004"/>
		<updated>2014-12-12T02:50:46Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: /* Available functions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The calculated question type could benefit of the EvalMath module to increase the math functions useable in the Calculated, Simple calculated et Multiple choice calculated question types.&lt;br /&gt;
==Available functions==&lt;br /&gt;
&lt;br /&gt;
Calculated questions can use more than simple arithmetic operators. The following functions are allowed in versions 1.5 and newer.&lt;br /&gt;
&lt;br /&gt;
{| width=&amp;quot;97%&amp;quot; border=&amp;quot;1px&amp;quot;&lt;br /&gt;
!Function&lt;br /&gt;
!1,5+&lt;br /&gt;
!Eval&lt;br /&gt;
Math&lt;br /&gt;
!2.9&lt;br /&gt;
!tested&lt;br /&gt;
!Explanation&lt;br /&gt;
|-&lt;br /&gt;
|abs&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Absolute value&lt;br /&gt;
|-&lt;br /&gt;
|acos&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Arc cosine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|acosh&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Inverse hyperbolic cosine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|asin&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Arc sine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|asinh&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Inverse hyperbolic sine.-- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|atan2&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Arc tangent of two variables -- pass in two values like (y, x), and you&#039;ll get the atan(y/x), adjusted to the proper quadrant. (Note: The variables are in the reverse order to atan2(x,y) in Excel) Output is radians.&lt;br /&gt;
|-&lt;br /&gt;
|atan&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Arc tangent -- output in radians.   &lt;br /&gt;
|-&lt;br /&gt;
|atanh&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Inverse hyperbolic tangent-- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|bindec&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Binary to decimal&lt;br /&gt;
|-&lt;br /&gt;
|ceil&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Round fractions up&lt;br /&gt;
|-&lt;br /&gt;
|cos&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Cosine -- in radians!!!  Convert your degree measurement to radians before you take the cos of it.&lt;br /&gt;
|-&lt;br /&gt;
|cosh&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Hyperbolic cosine -- in radians!!!  Convert your degree measurement to radians before you take the cosh of it.&lt;br /&gt;
|-&lt;br /&gt;
|decbin&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Decimal to binary&lt;br /&gt;
|-&lt;br /&gt;
|decoct&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Decimal to octal&lt;br /&gt;
|-&lt;br /&gt;
|deg2rad&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Converts the number in degrees to the radian equivalent&lt;br /&gt;
|-&lt;br /&gt;
|exp&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Calculates the exponent of e&lt;br /&gt;
|-&lt;br /&gt;
|expm1&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Returns exp(number) - 1, computed in a way that is accurate even when the value of number is close to zero&lt;br /&gt;
|-&lt;br /&gt;
|floor&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Round fractions down&lt;br /&gt;
|-&lt;br /&gt;
|fmod&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Returns the floating-point modulus of two numbers - i.e. the remainder when the first is divided by the second.&lt;br /&gt;
|-&lt;br /&gt;
|is_finite&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Finds whether a value is a legal finite number&lt;br /&gt;
|-&lt;br /&gt;
|is_infinite&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Finds whether a value is infinite&lt;br /&gt;
|-&lt;br /&gt;
|is_nan&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Finds whether a value is not a number&lt;br /&gt;
|-&lt;br /&gt;
|log10&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Base-10 logarithm&lt;br /&gt;
|-&lt;br /&gt;
|log1p&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Returns log(1 + number), computed in a way that is accurate even when the value of number is close to zero&lt;br /&gt;
|-&lt;br /&gt;
|log&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Natural logarithm (&#039;&#039;ln&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
|max&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Find highest value&lt;br /&gt;
|-&lt;br /&gt;
|min&lt;br /&gt;
|Find lowest value&lt;br /&gt;
|-&lt;br /&gt;
|octdec&lt;br /&gt;
|Octal to decimal&lt;br /&gt;
|-&lt;br /&gt;
|pi()&lt;br /&gt;
|Get value of pi - the function does not take an argument, like in Excel.&lt;br /&gt;
|-&lt;br /&gt;
|pow (numberToRaise, NumberRaisedTo)&lt;br /&gt;
|Exponential expression&lt;br /&gt;
|-&lt;br /&gt;
|rad2deg&lt;br /&gt;
|Converts the radian number to the equivalent number in degrees&lt;br /&gt;
|-&lt;br /&gt;
|rand&lt;br /&gt;
|Generate a random integer&lt;br /&gt;
|-&lt;br /&gt;
|round&lt;br /&gt;
|Rounds a float&lt;br /&gt;
|-&lt;br /&gt;
|sin&lt;br /&gt;
|Sine -- in radians!!!  Convert your degree measurement to radians before you take the sin of it.&lt;br /&gt;
|-&lt;br /&gt;
|sinh&lt;br /&gt;
|Hyperbolic sine -- in radians!!!  Convert your degree measurement to radians before you take the sinh of it.&lt;br /&gt;
|-&lt;br /&gt;
|sqrt&lt;br /&gt;
|Square root&lt;br /&gt;
|-&lt;br /&gt;
|tan&lt;br /&gt;
|Tangent -- in radians!!!  Convert your degree measurement to radians before you take the tan of it.&lt;br /&gt;
|-&lt;br /&gt;
|tanh&lt;br /&gt;
|Hyperbolic tangent -- in radians!!!  Convert your degree measurement to radians before you take the tanh of it.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Calculated_question_:_adding_new_math_functions&amp;diff=47003</id>
		<title>Calculated question : adding new math functions</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Calculated_question_:_adding_new_math_functions&amp;diff=47003"/>
		<updated>2014-12-12T02:39:40Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: /* Available functions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The calculated question type could benefit of the EvalMath module to increase the math functions useable in the Calculated, Simple calculated et Multiple choice calculated question types.&lt;br /&gt;
==Available functions==&lt;br /&gt;
&lt;br /&gt;
Calculated questions can use more than simple arithmetic operators. The following functions are allowed in versions 1.5 and newer.&lt;br /&gt;
&lt;br /&gt;
{| width=&amp;quot;97%&amp;quot; border=&amp;quot;1px&amp;quot;&lt;br /&gt;
!Function&lt;br /&gt;
!1,5+&lt;br /&gt;
!Eval&lt;br /&gt;
Math&lt;br /&gt;
!2.9&lt;br /&gt;
!tested&lt;br /&gt;
!Explanation&lt;br /&gt;
|-&lt;br /&gt;
|abs&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Absolute value&lt;br /&gt;
|-&lt;br /&gt;
|acos&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Arc cosine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|acosh&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Inverse hyperbolic cosine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|asin&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Arc sine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|asinh&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Inverse hyperbolic sine.-- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|atan2&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Arc tangent of two variables -- pass in two values like (y, x), and you&#039;ll get the atan(y/x), adjusted to the proper quadrant. (Note: The variables are in the reverse order to atan2(x,y) in Excel) Output is radians.&lt;br /&gt;
|-&lt;br /&gt;
|atan&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Arc tangent -- output in radians.   &lt;br /&gt;
|-&lt;br /&gt;
|atanh&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Inverse hyperbolic tangent-- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|bindec&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Binary to decimal&lt;br /&gt;
|-&lt;br /&gt;
|ceil&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Round fractions up&lt;br /&gt;
|-&lt;br /&gt;
|cos&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Cosine -- in radians!!!  Convert your degree measurement to radians before you take the cos of it.&lt;br /&gt;
|-&lt;br /&gt;
|cosh&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Hyperbolic cosine -- in radians!!!  Convert your degree measurement to radians before you take the cosh of it.&lt;br /&gt;
|-&lt;br /&gt;
|decbin&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Decimal to binary&lt;br /&gt;
|-&lt;br /&gt;
|decoct&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Decimal to octal&lt;br /&gt;
|-&lt;br /&gt;
|deg2rad&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Converts the number in degrees to the radian equivalent&lt;br /&gt;
|-&lt;br /&gt;
|exp&lt;br /&gt;
|Calculates the exponent of e&lt;br /&gt;
|-&lt;br /&gt;
|expm1&lt;br /&gt;
|Returns exp(number) - 1, computed in a way that is accurate even when the value of number is close to zero&lt;br /&gt;
|-&lt;br /&gt;
|floor&lt;br /&gt;
|Round fractions down&lt;br /&gt;
|-&lt;br /&gt;
|fmod&lt;br /&gt;
|Returns the floating-point modulus of two numbers - i.e. the remainder when the first is divided by the second.&lt;br /&gt;
|-&lt;br /&gt;
|is_finite&lt;br /&gt;
|Finds whether a value is a legal finite number&lt;br /&gt;
|-&lt;br /&gt;
|is_infinite&lt;br /&gt;
|Finds whether a value is infinite&lt;br /&gt;
|-&lt;br /&gt;
|is_nan&lt;br /&gt;
|Finds whether a value is not a number&lt;br /&gt;
|-&lt;br /&gt;
|log10&lt;br /&gt;
|Base-10 logarithm&lt;br /&gt;
|-&lt;br /&gt;
|log1p&lt;br /&gt;
|Returns log(1 + number), computed in a way that is accurate even when the value of number is close to zero&lt;br /&gt;
|-&lt;br /&gt;
|log&lt;br /&gt;
|Natural logarithm (&#039;&#039;ln&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
|max&lt;br /&gt;
|Find highest value&lt;br /&gt;
|-&lt;br /&gt;
|min&lt;br /&gt;
|Find lowest value&lt;br /&gt;
|-&lt;br /&gt;
|octdec&lt;br /&gt;
|Octal to decimal&lt;br /&gt;
|-&lt;br /&gt;
|pi()&lt;br /&gt;
|Get value of pi - the function does not take an argument, like in Excel.&lt;br /&gt;
|-&lt;br /&gt;
|pow (numberToRaise, NumberRaisedTo)&lt;br /&gt;
|Exponential expression&lt;br /&gt;
|-&lt;br /&gt;
|rad2deg&lt;br /&gt;
|Converts the radian number to the equivalent number in degrees&lt;br /&gt;
|-&lt;br /&gt;
|rand&lt;br /&gt;
|Generate a random integer&lt;br /&gt;
|-&lt;br /&gt;
|round&lt;br /&gt;
|Rounds a float&lt;br /&gt;
|-&lt;br /&gt;
|sin&lt;br /&gt;
|Sine -- in radians!!!  Convert your degree measurement to radians before you take the sin of it.&lt;br /&gt;
|-&lt;br /&gt;
|sinh&lt;br /&gt;
|Hyperbolic sine -- in radians!!!  Convert your degree measurement to radians before you take the sinh of it.&lt;br /&gt;
|-&lt;br /&gt;
|sqrt&lt;br /&gt;
|Square root&lt;br /&gt;
|-&lt;br /&gt;
|tan&lt;br /&gt;
|Tangent -- in radians!!!  Convert your degree measurement to radians before you take the tan of it.&lt;br /&gt;
|-&lt;br /&gt;
|tanh&lt;br /&gt;
|Hyperbolic tangent -- in radians!!!  Convert your degree measurement to radians before you take the tanh of it.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Calculated_question_:_adding_new_math_functions&amp;diff=47002</id>
		<title>Calculated question : adding new math functions</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Calculated_question_:_adding_new_math_functions&amp;diff=47002"/>
		<updated>2014-12-12T02:32:49Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: Created page with &amp;quot;The calculated question type could benefit of the EvalMath module to increase the math functions useable in the Calculated, Simple calculated et Multiple choice calculated que...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The calculated question type could benefit of the EvalMath module to increase the math functions useable in the Calculated, Simple calculated et Multiple choice calculated question types.&lt;br /&gt;
==Available functions==&lt;br /&gt;
&lt;br /&gt;
Calculated questions can use more than simple arithmetic operators. The following functions are allowed in versions 1.5 and newer.&lt;br /&gt;
&lt;br /&gt;
{| width=&amp;quot;97%&amp;quot; border=&amp;quot;1px&amp;quot;&lt;br /&gt;
!Function&lt;br /&gt;
!Explanation&lt;br /&gt;
|-&lt;br /&gt;
|abs&lt;br /&gt;
|Absolute value&lt;br /&gt;
|-&lt;br /&gt;
|acos&lt;br /&gt;
|Arc cosine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|acosh&lt;br /&gt;
|Inverse hyperbolic cosine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|asin&lt;br /&gt;
|Arc sine -- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|asinh&lt;br /&gt;
|Inverse hyperbolic sine.-- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|atan2&lt;br /&gt;
|Arc tangent of two variables -- pass in two values like (y, x), and you&#039;ll get the atan(y/x), adjusted to the proper quadrant. (Note: The variables are in the reverse order to atan2(x,y) in Excel) Output is radians.&lt;br /&gt;
|-&lt;br /&gt;
|atan&lt;br /&gt;
|Arc tangent -- output in radians.   &lt;br /&gt;
|-&lt;br /&gt;
|atanh&lt;br /&gt;
|Inverse hyperbolic tangent-- output in radians.&lt;br /&gt;
|-&lt;br /&gt;
|bindec&lt;br /&gt;
|Binary to decimal&lt;br /&gt;
|-&lt;br /&gt;
|ceil&lt;br /&gt;
|Round fractions up&lt;br /&gt;
|-&lt;br /&gt;
|cos&lt;br /&gt;
|Cosine -- in radians!!!  Convert your degree measurement to radians before you take the cos of it.&lt;br /&gt;
|-&lt;br /&gt;
|cosh&lt;br /&gt;
|Hyperbolic cosine -- in radians!!!  Convert your degree measurement to radians before you take the cosh of it.&lt;br /&gt;
|-&lt;br /&gt;
|decbin&lt;br /&gt;
|Decimal to binary&lt;br /&gt;
|-&lt;br /&gt;
|decoct&lt;br /&gt;
|Decimal to octal&lt;br /&gt;
|-&lt;br /&gt;
|deg2rad&lt;br /&gt;
|Converts the number in degrees to the radian equivalent&lt;br /&gt;
|-&lt;br /&gt;
|exp&lt;br /&gt;
|Calculates the exponent of e&lt;br /&gt;
|-&lt;br /&gt;
|expm1&lt;br /&gt;
|Returns exp(number) - 1, computed in a way that is accurate even when the value of number is close to zero&lt;br /&gt;
|-&lt;br /&gt;
|floor&lt;br /&gt;
|Round fractions down&lt;br /&gt;
|-&lt;br /&gt;
|fmod&lt;br /&gt;
|Returns the floating-point modulus of two numbers - i.e. the remainder when the first is divided by the second.&lt;br /&gt;
|-&lt;br /&gt;
|is_finite&lt;br /&gt;
|Finds whether a value is a legal finite number&lt;br /&gt;
|-&lt;br /&gt;
|is_infinite&lt;br /&gt;
|Finds whether a value is infinite&lt;br /&gt;
|-&lt;br /&gt;
|is_nan&lt;br /&gt;
|Finds whether a value is not a number&lt;br /&gt;
|-&lt;br /&gt;
|log10&lt;br /&gt;
|Base-10 logarithm&lt;br /&gt;
|-&lt;br /&gt;
|log1p&lt;br /&gt;
|Returns log(1 + number), computed in a way that is accurate even when the value of number is close to zero&lt;br /&gt;
|-&lt;br /&gt;
|log&lt;br /&gt;
|Natural logarithm (&#039;&#039;ln&#039;&#039;)&lt;br /&gt;
|-&lt;br /&gt;
|max&lt;br /&gt;
|Find highest value&lt;br /&gt;
|-&lt;br /&gt;
|min&lt;br /&gt;
|Find lowest value&lt;br /&gt;
|-&lt;br /&gt;
|octdec&lt;br /&gt;
|Octal to decimal&lt;br /&gt;
|-&lt;br /&gt;
|pi()&lt;br /&gt;
|Get value of pi - the function does not take an argument, like in Excel.&lt;br /&gt;
|-&lt;br /&gt;
|pow (numberToRaise, NumberRaisedTo)&lt;br /&gt;
|Exponential expression&lt;br /&gt;
|-&lt;br /&gt;
|rad2deg&lt;br /&gt;
|Converts the radian number to the equivalent number in degrees&lt;br /&gt;
|-&lt;br /&gt;
|rand&lt;br /&gt;
|Generate a random integer&lt;br /&gt;
|-&lt;br /&gt;
|round&lt;br /&gt;
|Rounds a float&lt;br /&gt;
|-&lt;br /&gt;
|sin&lt;br /&gt;
|Sine -- in radians!!!  Convert your degree measurement to radians before you take the sin of it.&lt;br /&gt;
|-&lt;br /&gt;
|sinh&lt;br /&gt;
|Hyperbolic sine -- in radians!!!  Convert your degree measurement to radians before you take the sinh of it.&lt;br /&gt;
|-&lt;br /&gt;
|sqrt&lt;br /&gt;
|Square root&lt;br /&gt;
|-&lt;br /&gt;
|tan&lt;br /&gt;
|Tangent -- in radians!!!  Convert your degree measurement to radians before you take the tan of it.&lt;br /&gt;
|-&lt;br /&gt;
|tanh&lt;br /&gt;
|Hyperbolic tangent -- in radians!!!  Convert your degree measurement to radians before you take the tanh of it.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Developer_notes&amp;diff=47001</id>
		<title>Developer notes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Developer_notes&amp;diff=47001"/>
		<updated>2014-12-12T02:25:52Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: /* Quiz &amp;amp; question types */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This area is for developers to work on various bits of code and documentation as necessary. Once material has matured it should be linked to from the main [[Developer documentation|Developer documentation]] page.&lt;br /&gt;
&lt;br /&gt;
==Core code==&lt;br /&gt;
&lt;br /&gt;
*[[Other lang issues|Language issues]] &lt;br /&gt;
*[[Datalib Notes]]&lt;br /&gt;
*[[Application/session variables]]&lt;br /&gt;
*[[Filters schema]]&lt;br /&gt;
*[[Filterall support]]&lt;br /&gt;
*[[Groups documentation for module developers]]&lt;br /&gt;
*[[Plan to improve ability to delegate administrator tasks to course category level|Plan to improve ability to delegate administrator tasks to course category level]]&lt;br /&gt;
*[[Stealth mode and nested activities|Stealth mode and nested activities]]&lt;br /&gt;
*[[Enrolment_plugins_2.0|How enrolments should work in Moodle 2.0]]&lt;br /&gt;
*[[Redesigning the override roles page|Redesigning the override roles page]]&lt;br /&gt;
&lt;br /&gt;
===Gradebook===&lt;br /&gt;
&lt;br /&gt;
*[[Gradebook_improvements|Gradebook improvements]] - ideas from Petr.&lt;br /&gt;
*[[Tim&#039;s_Gradebook_thoughts|Tim&#039;s Gradebook thoughts]]&lt;br /&gt;
&lt;br /&gt;
==Modules and other recognised plugin types==&lt;br /&gt;
&lt;br /&gt;
===Lesson===&lt;br /&gt;
&lt;br /&gt;
*[[Adding_question_types_to_lesson|Adding question types to lesson module]]&lt;br /&gt;
*[[New lesson navigation | New lesson navigation]]&lt;br /&gt;
*[[Adding blocks to lesson | Adding blocks to lesson]]&lt;br /&gt;
&lt;br /&gt;
===Quiz &amp;amp; question types===&lt;br /&gt;
&lt;br /&gt;
* [[File storage conversion Quiz and Questions|File storage conversion Quiz and Questions]] - notes for MDL-16094.&lt;br /&gt;
* [[How the quiz navigation should work in Moodle 2.0|How the quiz navigation should work in Moodle 2.0]] - MDL-20276.&lt;br /&gt;
* [[Moodle 2.0 question bank improvements|Moodle 2.0 question bank improvements]] - including question tagging and improved searchability.&lt;br /&gt;
* [[Question_Engine_2|Proposal to change the Moodle Question Engine]] This supersedes &lt;br /&gt;
** [[Plans for adaptive mode|Plans for adaptive mode]]&lt;br /&gt;
** [[Implementation of true negative marks in MC-type questions|Implementation of true negative marks in MC-type questions]]&lt;br /&gt;
* [[Calculated question : adding new math functions]]&lt;br /&gt;
* [[Numerical question units and intervals]]&lt;br /&gt;
* [[Future question bank/sharing/versioning requirements|Future question bank/sharing/versioning requirements]]&lt;br /&gt;
* [[States of a quiz attempt]]&lt;br /&gt;
* [[Optional checkbox &amp;quot;This is all my own work&amp;quot; before submitting a quiz]]&lt;br /&gt;
* [[The OU PMatch algorithm]]&lt;br /&gt;
* [[Provide print option for a Quiz]]&lt;br /&gt;
&lt;br /&gt;
===Other activity modules===&lt;br /&gt;
&lt;br /&gt;
*[[Forum development|Forum functional upgrade]]&lt;br /&gt;
*[[Wiki development|Wiki module development]]&lt;br /&gt;
*[[Schedule development|Proposed replacement for Scheduler]]&lt;br /&gt;
&lt;br /&gt;
===Gradebook Plugins===&lt;br /&gt;
&lt;br /&gt;
*[[External Database Plugin]]&lt;br /&gt;
&lt;br /&gt;
===Other===&lt;br /&gt;
&lt;br /&gt;
*[[Blogs and forums|Blogs, forums and the nature of discussion]]&lt;br /&gt;
*[[Conditional activities]]&lt;br /&gt;
*[[Improved Payment Plugin]]&lt;br /&gt;
*[[Moodle-specific customisations to the HTML editor]]&lt;br /&gt;
*[[Moodle Automatic Regression Test and Inspection Nit-picker]]&lt;br /&gt;
*[[ VSTU projects|Projects developed in Volgograd State Technical University]] becomes to many to simple list them on that page.&lt;br /&gt;
&lt;br /&gt;
== Markup &amp;amp; Theming ==&lt;br /&gt;
* [[Moodle CSS System]], idea from forum discussion on [http://moodle.org/mod/forum/discuss.php?d=126009 Object Oriented CSS]&lt;br /&gt;
&lt;br /&gt;
==Other==&lt;br /&gt;
&lt;br /&gt;
*[[MoodleDocs development]]&lt;br /&gt;
*[[Usability]]&lt;br /&gt;
*[[Document Management API]]&lt;br /&gt;
*[[wikindx|Possible integration of WIKINDX with Moodle]]&lt;br /&gt;
*[[Snapshot - flat HTML export of complete course]]&lt;br /&gt;
*[[Offline Moodle | Development:Offline Moodle - A Moodle that runs on a mobile device with the internet]]&lt;br /&gt;
*[[A standard set of fixtures for unit tests?|A standard set of fixtures for unit tests?]]&lt;br /&gt;
*[[reportbuilder|Possible integration Totara Report Builder into Moodle]]&lt;br /&gt;
*[[openbadges|Open Badges]]&lt;br /&gt;
*[[Course Reset Proposal]]&lt;br /&gt;
&lt;br /&gt;
==Archive: past proposals==&lt;br /&gt;
&lt;br /&gt;
===Things that got implemented===&lt;br /&gt;
&lt;br /&gt;
====Core code====&lt;br /&gt;
&lt;br /&gt;
*[[Ajax user selector|Ajax user selector]]&lt;br /&gt;
*[[Roles]] - in Moodle 1.7&lt;br /&gt;
*[[Moodle forms library]] - in Moodle 1.8&lt;br /&gt;
**[[Martin form notes]]&lt;br /&gt;
&lt;br /&gt;
====Quiz &amp;amp; question types====&lt;br /&gt;
&lt;br /&gt;
*[[Quiz UI redesign | Quiz UI redesign]]&lt;br /&gt;
*[[Administration page for question types|Administration page for question types]]&lt;br /&gt;
*[[Plan_to_Improve_Flexibility_of_Question_Category_Sharing_and_Permissions|Plans for enhancing the question bank]] - in Moodle 1.9&lt;br /&gt;
*[[Email notification when a quiz is submitted|Email notification when a quiz is submitted]] - in Moodle 1.9&lt;br /&gt;
*[[Plans for enhancing import/export in questiontype plugins]] - in Moodle 1.9&lt;br /&gt;
*[[quiz_navigation | Quiz navigation]]&lt;br /&gt;
*[[Open_protocol_for_accessing_question_engines|Open protocol for accessing question engines]]&lt;br /&gt;
*[[Quiz report enhancements|Quiz report enhancements]]&lt;br /&gt;
*[[Flagging questions during a quiz attempt|Flagging questions during a quiz attempt]]&lt;br /&gt;
&lt;br /&gt;
====Other====&lt;br /&gt;
&lt;br /&gt;
*[[Quiz and quesions community testing day]]&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_formats&amp;diff=37137</id>
		<title>Question Engine 2:Numerical formats</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_formats&amp;diff=37137"/>
		<updated>2013-01-09T17:21:29Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: /* Numbers */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The Question Engine 2 structure allows implementation of new features for numerical question types ( numerical and calculated).&lt;br /&gt;
&lt;br /&gt;
This page describes a possible implementation and its rationale.&lt;br /&gt;
&lt;br /&gt;
The text should be readed as a personal summary of the work in progress and not as a textbook on computer language and real numbers representation.&lt;br /&gt;
&lt;br /&gt;
It is related to an initial quiz forum discussion &lt;br /&gt;
http://moodle.org/mod/forum/discuss.php?d=172211#p755927&lt;br /&gt;
&lt;br /&gt;
Please put your comments on the forum.&lt;br /&gt;
http://moodle.org/mod/forum/discuss.php?d=174387&lt;br /&gt;
&lt;br /&gt;
See also http://tracker.moodle.org/browse/MDL-2736&lt;br /&gt;
&lt;br /&gt;
See also [[Question Engine 2:Numerical questions]]&lt;br /&gt;
&lt;br /&gt;
==Numerical question grading ==&lt;br /&gt;
&lt;br /&gt;
There are 3 elements that can be graded in a numerical question&lt;br /&gt;
# the numeric value&lt;br /&gt;
# the unit used in relation to the numeric value&lt;br /&gt;
# the number format used to express the value&lt;br /&gt;
&lt;br /&gt;
1 and 2 are addressed in Moodle 2,0 for questions created from edit_numerical_form.php.&lt;br /&gt;
 &lt;br /&gt;
3 can give a 0 grade if the student does not use one of the number formats allowed but there is no specific grading designed as the unit penalty since Moodle 2,0.&lt;br /&gt;
&lt;br /&gt;
==How to design the code flow for grading a numerical question==&lt;br /&gt;
&lt;br /&gt;
Ideally we should be able to sinulate the teacher grading approach which is about the following&lt;br /&gt;
# Find the numerical characters (+-123456...) and translate them in a number following locale numbering style(s) allowed to the students response. To be fair the style should be known to the students if they are different from their usual langage number style.&lt;br /&gt;
# Compare the translated number to the numerical good answer or the equivalent if they are expressed in authorized units allowed.&lt;br /&gt;
# Identify the units part of the response and verify if it is well written and one of the in authorized units allowed&lt;br /&gt;
# Verify if the unit is the correct one to use so that the response express the numerical value of the answer.&lt;br /&gt;
&lt;br /&gt;
===Identify the number in the response===&lt;br /&gt;
&lt;br /&gt;
The more variant ways you allow in expressing the numerical value, the more complex will be the decoding process.&lt;br /&gt;
&lt;br /&gt;
When a teacher decode a student response, he can pinpoint errors in the number writing and exptract the most plausible numerical value from student response and grade separately the numerical value from the errors in the number syntax using a more or less complex grading approach.&lt;br /&gt;
&lt;br /&gt;
===Compare the response numerical value to answer numerical value===&lt;br /&gt;
This comparison is easily done in computer code and the moodle code allow to set different tolerance and can even the teacher can even set another answer related to a common error (i.e. 2 * ) and give a specific grade.&lt;br /&gt;
&lt;br /&gt;
===Identify the unit in the response===&lt;br /&gt;
Here the actual moodle code is quite limited as are limited the unit syntax that can be used.&lt;br /&gt;
Just think of expressing a surface in  squared mm&lt;br /&gt;
This is why the multiple choice variant was added in 2,0 as the teacher could set complex math formula in the question text that the student could choose.&lt;br /&gt;
&lt;br /&gt;
The numerical syntax is not the main objective of the numerical question and given the limits of the pattern recognition performance of the code, the use of two input fields (number and unit) to help the student to express the two part of the response as it helps moodle to identify them correctly. &lt;br /&gt;
&lt;br /&gt;
It allows also the &lt;br /&gt;
# the use of more variant forms of expressing the numerical values ( fractions, time, degress)&lt;br /&gt;
# development of specific tool to express complex unities.&lt;br /&gt;
&lt;br /&gt;
===The events in the decoding steps===&lt;br /&gt;
Given the new opportunities of the new engine qtype_numerical_walkthrough that extends qbehaviour_walkthrough, the code should reflect the different results obtained in the response analysis.&lt;br /&gt;
&lt;br /&gt;
This is not an easy task that will complexify each time we will allow more flexibility in number and units formats.&lt;br /&gt;
&lt;br /&gt;
====Identify the number in the response====&lt;br /&gt;
Find the numerical characters (+-123456...) and translate them in a number following locale numbering style(s) allowed to the students response. To be fair the style should be known to the students if it&#039;s  different from their current language usage ( help icon).&lt;br /&gt;
&lt;br /&gt;
Given the identified response input element , the code can detect that there are additional characters that are not used in the extracted number but this could result from accidental typing error but most often from badly written number which most will have its own penalty when grading for the numerical value.&lt;br /&gt;
&lt;br /&gt;
====Identify the unit in the response====&lt;br /&gt;
Identify the units part of the response. &lt;br /&gt;
There is no easy syntax analysis to detect syntax errors.&lt;br /&gt;
# field empty&lt;br /&gt;
# the correspondance with one units set in the question can be (and is)done later.&lt;br /&gt;
&lt;br /&gt;
====Compare the response numerical value to answer numerical value using the units factor====&lt;br /&gt;
Compare the translated number to the numerical good answer or the equivalent if they are expressed in authorized units allowed.&lt;br /&gt;
&lt;br /&gt;
This is done with the result that report the grade and the unit used to set the grade.&lt;br /&gt;
&lt;br /&gt;
====Verify if the unit from the response is the one used in setting the numerical grade====&lt;br /&gt;
Verify &lt;br /&gt;
# if the unit is well written and one of the in authorized units allowed.&lt;br /&gt;
# if the unit is the correct one to use so that the response express the numerical value of the answer.&lt;br /&gt;
&lt;br /&gt;
The unit_penalty reflects this step but a different message should be given following the 2 cases although the second one cannot happen with multichoice option.&lt;br /&gt;
&lt;br /&gt;
==The different number formats==&lt;br /&gt;
Numerical quantity can be expresed as&lt;br /&gt;
#  Integer without decsep and with or without thousandseps  (many combinations related to number locale)  as 1234  1 234&lt;br /&gt;
#  Decimal with a decsep ( either , or . ) and with or without thousandseps (many combinations related to number locale)  as 1234.456  1 234,456 &lt;br /&gt;
#  Exponent form with a decsep ( either , or . ) and without  thousandseps ? as 1.23456 E3&lt;br /&gt;
#  Fractional form the dessep is &#039; &#039;  and without  thousandseps  as 1234 456/1000&lt;br /&gt;
#  Angles as degree minute second&lt;br /&gt;
#  Time as hour:minute:second&lt;br /&gt;
# Etc.&lt;br /&gt;
&lt;br /&gt;
The international locale parameters defined are mainly related to the decimal form and constitue a long list as they are related mostly to the language.&lt;br /&gt;
&lt;br /&gt;
I propose that we do not define our number parameters to these locale although in the help we could relate the decsep and tousand to the international locales.&lt;br /&gt;
&lt;br /&gt;
The 2,0 formats allowed simultaneously by apply_unit() function are&lt;br /&gt;
&lt;br /&gt;
#  Integer without decsep and with or without thousandseps  (many combinations related to number locale)  as 1234  1 234&lt;br /&gt;
#  Decimal with a decsep ( either , or . ) and with or without thousandseps ( &#039; &#039; or &#039;,&#039; if decsep == &#039;.&#039; )  as 1234.456  1 234,456 &lt;br /&gt;
#  Exponent form with a decsep ( either , or . ) and with  thousandseps  ( &#039; &#039; or &#039;,&#039; if decsep == &#039;.&#039; ) as 1.23456 E3&lt;br /&gt;
&lt;br /&gt;
in 1,9 the decsep &#039;,&#039; was not allowed&lt;br /&gt;
&lt;br /&gt;
==Identify the number in the response==&lt;br /&gt;
&lt;br /&gt;
The function apply_value($response,$unit) used to identify the number unit combination and retrun the numerical value for grading as evolved in the different moodle version allowing more complete number analysis but without a significant output to apply a number format penalty other than 0 or 1 value.&lt;br /&gt;
&lt;br /&gt;
Grading the different formats can be applied either at the &lt;br /&gt;
=== the question level===&lt;br /&gt;
 using a more complex number analysis with an output that can be used to apply a number format penalty&lt;br /&gt;
&lt;br /&gt;
===  the answer level.===&lt;br /&gt;
As grading is done at the answer level adding an additional element to the answer (i.e. tolerance) was first explored as a solution.see lower in this page https://docs.moodle.org/en/Development:Question_Engine_2:Numerical_formats#How_to_grade_a_numerical_response_format&lt;br /&gt;
However this solution implies that the user set the number format analysis pattern to apply.&lt;br /&gt;
&lt;br /&gt;
So improving the flexibility of the number analysis at the question level appers as a better solution&lt;br /&gt;
&lt;br /&gt;
==Improving the number analysis at the question level==&lt;br /&gt;
&lt;br /&gt;
To apply a more complete number analysis we need at least the following parameters that should be stored in a new database table.&lt;br /&gt;
# usual id and question&lt;br /&gt;
# the name of the analysis (either specific as &#039;decimal&#039; or a mixed combination )&lt;br /&gt;
# the order in this variant in the analysis and the grade associated with the result as&lt;br /&gt;
## decsep = . with thousand = ,   and grade 100% of the given answer fraction&lt;br /&gt;
## decsep = . with thousand = &#039; &#039;  and grade 90% of the given answer fraction&lt;br /&gt;
## decsep all and and grade 80% of the given answer fraction&lt;br /&gt;
# params used in this numerical variant most often decsep and thousands but could be also the exponential form (alloed or not) or new ones like / for fraction.&lt;br /&gt;
&lt;br /&gt;
The field &#039;name&#039; should be related to a  number class that can handle the necessary grading, saving and retrieving steps.&lt;br /&gt;
&lt;br /&gt;
We need to define these number classes before going further [[User:Pierre Pichet|Pierre Pichet]] 15:30, 31 May 2011 (WST)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 if ($oldversion &amp;lt; 2011052200 ) { //New version in version.php&lt;br /&gt;
&lt;br /&gt;
    /// Define table question_numerical_options to be created&lt;br /&gt;
        $table = new xmldb_table(&#039;question_numerical_formats&#039;);&lt;br /&gt;
&lt;br /&gt;
    /// Adding fields to table question_numerical_formats &lt;br /&gt;
       $table-&amp;gt;add_field(&#039;id&#039;, XMLDB_TYPE_INTEGER, &#039;10&#039;, XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);&lt;br /&gt;
        $table-&amp;gt;add_field(&#039;question&#039;, XMLDB_TYPE_INTEGER, &#039;10&#039;, XMLDB_UNSIGNED, XMLDB_NOTNULL, null, &#039;0&#039;);&lt;br /&gt;
        $table-&amp;gt;add_field(&#039;name&#039;, XMLDB_TYPE_TEXT, &#039;small&#039;, null, null, null, null);&lt;br /&gt;
        $table-&amp;gt;add_field(&#039;order&#039;, XMLDB_TYPE_INTEGER, &#039;10&#039;, XMLDB_UNSIGNED, XMLDB_NOTNULL, null, &#039;0&#039;);&lt;br /&gt;
        $table-&amp;gt;add_field(&#039;grade&#039;, XMLDB_TYPE_NUMBER, &#039;12, 7&#039;, XMLDB_UNSIGNED, XMLDB_NOTNULL, null, &#039;0&#039;);&lt;br /&gt;
        $table-&amp;gt;add_field(&#039;params&#039;, XMLDB_TYPE_TEXT, &#039;small&#039;, null, null, null, null);&lt;br /&gt;
&lt;br /&gt;
    /// Adding keys to table question_numerical_formats&lt;br /&gt;
        $table-&amp;gt;add_key(&#039;primary&#039;, XMLDB_KEY_PRIMARY, array(&#039;id&#039;));&lt;br /&gt;
        $table-&amp;gt;add_key(&#039;question&#039;, XMLDB_KEY_FOREIGN, array(&#039;question&#039;), &#039;question&#039;, array(&#039;id&#039;));&lt;br /&gt;
    /// Conditionally launch create table for question_calculated_options&lt;br /&gt;
        if (!$dbman-&amp;gt;table_exists($table)) {&lt;br /&gt;
            // $dbman-&amp;gt;create_table doesnt return a result, we just have to trust it&lt;br /&gt;
            $dbman-&amp;gt;create_table($table);&lt;br /&gt;
        }&lt;br /&gt;
        upgrade_plugin_savepoint(true, 2011052200, &#039;qtype&#039;, &#039;numerical&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The info about the different parameters ( like the official locales decsep amd thousandsep ) and analysis coding could be stored in an additional numerical/number_analysis.php file&lt;br /&gt;
&lt;br /&gt;
 When sufficiently developped, this number analysis code should become a question engine function or type i.e graded as ...&lt;br /&gt;
&lt;br /&gt;
==Implementing in 2,1 release==&lt;br /&gt;
&lt;br /&gt;
Given the delays we need to set the minimal changes that will set the necessary code structure for allowing the various aspects discussed in the upper part of this page even if as a first version we do not all of them.&lt;br /&gt;
===Locale ( i.e decsep) is defined at the question level not at the site level===&lt;br /&gt;
We need &lt;br /&gt;
# set the locale parameters in a question related database table (i.e. as unit are)&lt;br /&gt;
## create the database structure&lt;br /&gt;
## the save and read functions&lt;br /&gt;
## create the edit_numererical_fomr code to set the paramters at the question level&lt;br /&gt;
## eliminate the construct functions that defined the locale default as site locale default&lt;br /&gt;
## set the apply_value code to multiple decseps and or thousandseps&lt;br /&gt;
## implement a minimal numerical format grading&lt;br /&gt;
### a first choice as either . or , decsep grade 100%&lt;br /&gt;
### a second choice as the other decsep  graded as desired (0-100%)  &lt;br /&gt;
## default the pretty number decsep to PHP standard i.e. &#039;.&#039; or the first choice . &lt;br /&gt;
&lt;br /&gt;
===Units===&lt;br /&gt;
&lt;br /&gt;
As the unit uses already a specific input field in 2,0 , we should continue this in 2,1 as in the future this will allow us maximum flexibility.&lt;br /&gt;
&lt;br /&gt;
Technically, we should use the coding structure developed by Tim in the multianswer renderer to continue the use of multichoice regular display as it allows HTML and even Latex rendering.&lt;br /&gt;
&lt;br /&gt;
We should implement unit grading as done in 2,0 i.e. the response numerical value is tested against the answer value using all defined units. &lt;br /&gt;
&lt;br /&gt;
We need to create the corresponding response states.&lt;br /&gt;
&lt;br /&gt;
==Numbers==&lt;br /&gt;
from http://en.wikipedia.org/wiki/Number&lt;br /&gt;
&lt;br /&gt;
The real numbers include all of the measuring numbers. Real numbers are usually written using [[decimal]] numerals, in which a decimal point is placed to the right of the digit with place value one. Each digit to the right of the decimal point has a place value one-tenth of the place value of the digit to its left.  &lt;br /&gt;
&lt;br /&gt;
Thus&lt;br /&gt;
&lt;br /&gt;
123.456&lt;br /&gt;
&lt;br /&gt;
represents 1 hundred, 2 tens, 3 ones, 4 tenths, 5 hundredths, and 6 thousandths.&lt;br /&gt;
&lt;br /&gt;
In the US and UK and a number of other countries, the decimal point is represented by a period, whereas in continental Europe and certain other countries the decimal point is represented by a comma. &lt;br /&gt;
&lt;br /&gt;
Zero is often written as 0.0 when it must be treated as a real number rather than an integer. &lt;br /&gt;
&lt;br /&gt;
In the US and UK a number between −1 and 1 is always written with a leading zero to emphasize the decimal. &lt;br /&gt;
&lt;br /&gt;
Negative real numbers are written with a preceding minus sign: -123.456.&lt;br /&gt;
&lt;br /&gt;
Every rational number is also a real number. It is not the case, however, that every real number is rational. If a real number cannot be written as a fraction of two integers, it is called irrational number. &lt;br /&gt;
&lt;br /&gt;
A decimal that can be written as a fraction either ends (terminates) or forever repeating decimal, because it is the answer to a problem in division. &lt;br /&gt;
&lt;br /&gt;
Thus the real number 0.5 can be written as 1/2 and the real number 0.333... (forever repeating threes, otherwise written 0.overline|3}}) can be written as 1/3.  On the other hand, the real number π , the ratio of the circumference of any circle to its diameter, is&lt;br /&gt;
pi = 3.14159265358979&lt;br /&gt;
Since the decimal neither ends nor forever repeats, it cannot be written as a fraction, and is an example of an irrational number. &lt;br /&gt;
&lt;br /&gt;
Thus 1.0 and 0.999... are two different decimal numerals representing the natural number 1.&lt;br /&gt;
&lt;br /&gt;
There are infinitely many other ways of representing the number 1, for example 2/2, 3/3, 1.00, 1.000, and so on.&lt;br /&gt;
&lt;br /&gt;
Every real number is either rational or irrational. Every real number corresponds to a point on the number line. &lt;br /&gt;
&lt;br /&gt;
When a real number represents a measurement, there is always a margin of error. This is often indicated by rounding or truncate|truncating a decimal, so that digits that suggest a greater accuracy than the measurement itself are removed.  The remaining digits are called significant digits. &lt;br /&gt;
&lt;br /&gt;
For example, measurements with a ruler can seldom be made without a margin of error of at least 0.01 meters. If the sides of a rectangle are measured as 1.23 meters and 4.56 meters, then multiplication gives an area for the rectangle of 5.6088 square meters. Since only the first two digits after the decimal place are significant, this is usually rounded to 5.61.&lt;br /&gt;
&lt;br /&gt;
see also &lt;br /&gt;
:http://en.wikipedia.org/wiki/Non-breaking_space&lt;br /&gt;
:http://en.wikipedia.org/wiki/Space_%28punctuation%29&lt;br /&gt;
&lt;br /&gt;
==Designing a number format penalty==&lt;br /&gt;
&lt;br /&gt;
We have already 2 ways to grade the student response available in the edit_numerical_form.php. i.e. &lt;br /&gt;
* the answer-tolerance combination&lt;br /&gt;
* the detailed unit grading &lt;br /&gt;
&lt;br /&gt;
We need flexibility to take in account that number format can vary even at a same location i.e. in Canada there are two locales as there are two official languages (french and english).&lt;br /&gt;
&lt;br /&gt;
Teacher sometimes ask for specific number formats as fraction that cannot be allowed simultanuously to other grading.&lt;br /&gt;
&lt;br /&gt;
The most universal solution is to associate a grade to a specific answer numerical format as the tolerance is used.&lt;br /&gt;
&lt;br /&gt;
For example in calculated the tolerance can be set as relative or absolute.&lt;br /&gt;
&lt;br /&gt;
So my proposal is to add the number format as a new answer parameter.&lt;br /&gt;
&lt;br /&gt;
To an official locales list of available formats we could add &lt;br /&gt;
* specific Moodle formats as the one used for 1,9 2,0 , &lt;br /&gt;
* a fraction format, &lt;br /&gt;
* time format, &lt;br /&gt;
* degree,  minute, second &lt;br /&gt;
* etc.&lt;br /&gt;
==Numbers as written by human and readed by computer language== &lt;br /&gt;
&lt;br /&gt;
The main feature of numerical question type is to ask the student to give a numerical answer i.e. a number.&lt;br /&gt;
Most often this means a numerical value that is not an integer ( dates are a current example of integer value response) but a real number which value is expressed most often as a decimal number i.e 1.234 .&lt;br /&gt;
&lt;br /&gt;
Computer languages ( i.e PHP used in Moodle) store real numbers in a different way than human do (decimal part and exponent similar to 1.234 E00) and humans do not expressed real nmumbers in an universal format.&lt;br /&gt;
&lt;br /&gt;
 The separator between the unit and the decimal fraction is often either a . or a ,  &lt;br /&gt;
 1.234   1,234&lt;br /&gt;
&lt;br /&gt;
Furthermore to help reading large numbers, most language add another separator for thousands often space or , if it is not used already as unit separator.&lt;br /&gt;
 123 456.78     123,456.78   123 456,78 &lt;br /&gt;
&lt;br /&gt;
PHP as a computer language use space to separate the language components so cannot use space as a thousand separator.&lt;br /&gt;
&lt;br /&gt;
, is also used to separate variables so PHP use a simpler syntax 123456.78.&lt;br /&gt;
&lt;br /&gt;
As this is stored in the computer as 2 parts (number and exponent).&lt;br /&gt;
 1.2345678+E05 will be a structure that is well recognized by a computer language as PHP.&lt;br /&gt;
&lt;br /&gt;
==Computers as dummy readers of human number writing==&lt;br /&gt;
&lt;br /&gt;
Ordinary peoples know from their experiences with  hand calculators or even sophisticated spreadsheets that computer are more or less &amp;quot;stupid&amp;quot; to recognized correctly the numbers or numerical values typed by humans.&lt;br /&gt;
&lt;br /&gt;
We as human need to know the number style that the computer will recognize as this can vary among the different computer usages.&lt;br /&gt;
&lt;br /&gt;
Typing a number in your on-line tax report is not the same as typing a number inside a complex math formula.&lt;br /&gt;
Tax reports will handle well various number formats i.e. &lt;br /&gt;
&lt;br /&gt;
# with or without the $ sign,  &lt;br /&gt;
# with or without the space or , as thousand separator&lt;br /&gt;
# will not accept exponential formating as $ 1e6 etc,&lt;br /&gt;
&lt;br /&gt;
However when writing a mathematical formula you cannot &lt;br /&gt;
# cannot put units i.e $ &lt;br /&gt;
#  space or , as thousands sep in numbers etc.&lt;br /&gt;
&lt;br /&gt;
Even if you type a number in a format, the computer could display it in another format.&lt;br /&gt;
&lt;br /&gt;
You type in a spreadsheet  =1e-3&lt;br /&gt;
 &lt;br /&gt;
On return the display could be 0.001 &lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;Number formats can be different following their usage : i.e tax reports and mathematical formula&#039;&#039;&#039;&lt;br /&gt;
 &lt;br /&gt;
 &#039;&#039;&#039;Humans have to learn which number format to use in a  given computer software case&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==Moodle 1,9 and 2,0 users and numbers  in a numerical and calculated question types ==&lt;br /&gt;
There are two main cases &lt;br /&gt;
=== The teacher setting the answer===&lt;br /&gt;
 &lt;br /&gt;
:in a numerical question answer&lt;br /&gt;
&lt;br /&gt;
::&#039;&#039;&#039;numerical questiontype IS NOT a shortanswer questiontype&#039;&#039;&#039; &lt;br /&gt;
:: At first sight we think that the number should be typed as the response that the student will type to have a full grade.&lt;br /&gt;
&lt;br /&gt;
:: If you want to do this, then you should use shortanswer questiontype.&lt;br /&gt;
&lt;br /&gt;
::&#039;&#039;&#039;In numerical questiontype the answer is a numerical value or quantity.&#039;&#039;&#039;&lt;br /&gt;
:: This is why we add tolerance grading to the numerical quantity.&lt;br /&gt;
&lt;br /&gt;
:: There is no case sensitivity in numerical question, case sensitivity in shortanswer question being the analogous to the numerical tolerance or vice versa...&lt;br /&gt;
&lt;br /&gt;
::  &#039;&#039;&#039; So when a teacher set the answer field ( and the tolerance field) in a numerical question he sets a value or a numerical quantity and PHP will understood this numercial quantity using a decimal format as 1234.56  or in exponential format as 1.23456 E3&#039;&#039;&#039; &lt;br /&gt;
::: notice that PHP in moodle always use . as decimal point.&lt;br /&gt;
::: in the edit_numerical_form or Gift import form these format with . are mandatory.&lt;br /&gt;
::: in cloze or other import the decimal point can be , in moodle 2,0.&lt;br /&gt;
&lt;br /&gt;
: in a calculated question formula answer&lt;br /&gt;
:: In calculated questiontype the numerical value or a numerical quantity will be obtained using a mathematical equation that among other element ( function, math symbol +-*/ etc.) will contain numerical quantities expressed as number.&lt;br /&gt;
::The number in the equation is written in strict PHP rule decimal format as 1234.56  or in exponential format as 1.23456 E3.&lt;br /&gt;
&lt;br /&gt;
=== The student typing its response in numerical or calculated question===&lt;br /&gt;
: in 1,9 the only decimal point allowed was .  &lt;br /&gt;
: in 2,0 the decimal point could be . or ,&lt;br /&gt;
: in 1,9 and 2,0 the thousands separator space or , (when decsep is .) where removed as need by PHP syntax.&lt;br /&gt;
&lt;br /&gt;
; THE EASIEST RULE FOR TEACHERS OR STUDENTS IS: ALWAYS USE PHP DECIMAL FORMAT  as 1234.56  or as 1.23456 E3;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; This also means that in the actual code when a teacher set the answer field , he DOES NOT set the response format&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Grading the response format : truth table==&lt;br /&gt;
&lt;br /&gt;
In the actual code 2,0 if the the decimal point and thousands sep are not set correctly by the student, he could have a zero grade to a correct numerical response.&lt;br /&gt;
&lt;br /&gt;
However a clever student will never use thousand separators and will learn once for all if he can use , or . as unit separator.&lt;br /&gt;
&lt;br /&gt;
The actual 2,1 proposal is to grade the numerical format separately from the numerical quantity.&lt;br /&gt;
&lt;br /&gt;
On analysis it appears that the best way to do this as there is already a unit penalty applied , is to add at least the decimal point as an additional answer parameter alongside the tolerance.&lt;br /&gt;
&lt;br /&gt;
A complete grading should also allow the teacher to specify the thousand separator as mandatory or control the use of the exponential format.&lt;br /&gt;
&lt;br /&gt;
given the time delays for 2,1, let&#039;s design a decimal decimal point option.&lt;br /&gt;
&lt;br /&gt;
The following table describe the results of the various versions&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle Version&lt;br /&gt;
! decsep&lt;br /&gt;
! thousand sep&lt;br /&gt;
! 1 234.56&lt;br /&gt;
! 1,234.56&lt;br /&gt;
! 1234.56&lt;br /&gt;
! 1.23456E3&lt;br /&gt;
! 1 234,56&lt;br /&gt;
! 1.234,56&lt;br /&gt;
! 1234,56&lt;br /&gt;
! 1,23456E3&lt;br /&gt;
|-&lt;br /&gt;
| 1,9&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
|-&lt;br /&gt;
| 2,0&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| NO&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
|-&lt;br /&gt;
| 2,1&lt;br /&gt;
| &#039;&#039;&#039;.&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039; ,&#039;&#039;&#039;&lt;br /&gt;
| NO&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
|-&lt;br /&gt;
| 2,1&lt;br /&gt;
| &#039;&#039;&#039;.&#039;&#039;&#039;&lt;br /&gt;
| space&lt;br /&gt;
| OK&lt;br /&gt;
| NO&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
|-&lt;br /&gt;
| 2,1&lt;br /&gt;
|&#039;&#039;&#039; ,&#039;&#039;&#039;&lt;br /&gt;
| space&lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
| OK&lt;br /&gt;
| NO&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
|-&lt;br /&gt;
| 2,1&lt;br /&gt;
|&#039;&#039;&#039; ,&#039;&#039;&#039;&lt;br /&gt;
|  .&lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
|-&lt;br /&gt;
| 2,1 proposal&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
|-&lt;br /&gt;
| 2,1 proposal&lt;br /&gt;
|  &#039;&#039;&#039;.&#039;&#039;&#039; &lt;br /&gt;
| &lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
|-&lt;br /&gt;
| 2,1proposal&lt;br /&gt;
|&#039;&#039;&#039; ,&#039;&#039;&#039;&lt;br /&gt;
| &lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
OR &lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle Version&lt;br /&gt;
! decsep&lt;br /&gt;
! thousand sep&lt;br /&gt;
! 1 234.56&lt;br /&gt;
! 1,234.56&lt;br /&gt;
! 1234.56&lt;br /&gt;
! 1.23456E3&lt;br /&gt;
! 1 234,56&lt;br /&gt;
! 1.234,56&lt;br /&gt;
! 1234,56&lt;br /&gt;
! 1,23456E3&lt;br /&gt;
|-&lt;br /&gt;
| 1,9&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 2,0&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| &lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
|-&lt;br /&gt;
| 2,1&lt;br /&gt;
| &#039;&#039;&#039;.&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039; ,&#039;&#039;&#039;&lt;br /&gt;
| &lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 2,1&lt;br /&gt;
| &#039;&#039;&#039;.&#039;&#039;&#039;&lt;br /&gt;
| space&lt;br /&gt;
| OK&lt;br /&gt;
| &lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 2,1&lt;br /&gt;
|&#039;&#039;&#039; ,&#039;&#039;&#039;&lt;br /&gt;
| space&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| OK&lt;br /&gt;
| &lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
|-&lt;br /&gt;
| 2,1&lt;br /&gt;
|&#039;&#039;&#039; ,&#039;&#039;&#039;&lt;br /&gt;
|  .&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
|-&lt;br /&gt;
| 2,1 proposal&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
|-&lt;br /&gt;
| 2,1 proposal&lt;br /&gt;
|  &#039;&#039;&#039;.&#039;&#039;&#039; &lt;br /&gt;
| &lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 2,1proposal&lt;br /&gt;
|&#039;&#039;&#039; ,&#039;&#039;&#039;&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
|}&lt;br /&gt;
In 2,1 there is no &#039;universal option&#039; that allow most of the known options and in 2,0 the german language 1.234,56 is not recognized.&lt;br /&gt;
&lt;br /&gt;
In 1,9 and 2,0 the PHP structure is always good&lt;br /&gt;
In 2,1 the PHP structure is good if you use the good thousands sep&lt;br /&gt;
&lt;br /&gt;
So there is no real  control on the thousand sep as long as the students learn to not using it.&lt;br /&gt;
&lt;br /&gt;
As a first step in grading the response format  in 2,1 , I propose that we limit the case to grade the decsep allowing either , or . and using a modified 2,0 version to handle the german . ,&lt;br /&gt;
&lt;br /&gt;
From the the table we can see, with the proposal, that upgrading or importing from 1,9 the default decsep should be set to .&lt;br /&gt;
and upgrading upgrading or importing from 2,0 the default decsep should be set to  nil i.e. universal.&lt;br /&gt;
&lt;br /&gt;
We could as set in 2,0 help warning the students that is they use , or . as thousand separators they MUST put the decimal separator.&lt;br /&gt;
&lt;br /&gt;
In 2,2 we could develop grading of thousand sep along  with the control of the exponential form.&lt;br /&gt;
&lt;br /&gt;
In all cases we need an &amp;quot;universal&amp;quot; solution for Cloze questiontype.&lt;br /&gt;
In calculated question the interface is already quite complex and perhaps things will not be implemented for 2,1 .&lt;br /&gt;
&lt;br /&gt;
==How to grade a numerical response format==&lt;br /&gt;
===Feasability of adding number format as an additional numerical answer table ===&lt;br /&gt;
&lt;br /&gt;
The answer field being set as TEXT can easily store a numerical value in any format that can be validated easily in  edit_numerical_form.php and the &lt;br /&gt;
 &amp;lt;code php&amp;gt;&lt;br /&gt;
    /**&lt;br /&gt;
     * Get an answer that contains the feedback and fraction that should be&lt;br /&gt;
     * awarded for this resonse.&lt;br /&gt;
     * @param number $value the numerical value of a response.&lt;br /&gt;
     * @return question_answer the matching answer.&lt;br /&gt;
     */&lt;br /&gt;
    public function get_matching_answer($value) {&lt;br /&gt;
        foreach ($this-&amp;gt;answers as $aid =&amp;gt; $answer) {&lt;br /&gt;
            if ($answer-&amp;gt;within_tolerance($value)) {&lt;br /&gt;
                $answer-&amp;gt;id = $aid;&lt;br /&gt;
                return $answer;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
 &amp;lt;/code&amp;gt;&lt;br /&gt;
modified accordingly.&lt;br /&gt;
&lt;br /&gt;
This is similar to tolerance handling which is another answer parameter .&lt;br /&gt;
&lt;br /&gt;
The code flow should allow to compare each answers to the different values that result from the response text.&lt;br /&gt;
&lt;br /&gt;
Aswers need to be compared with the value converted using the apply_unit() which could be different form the decsep value used, then either the $value is an array of all the values from the different decseps or the numerical value is computed inside this function from the student text response.&lt;br /&gt;
This later option could be the most flexible if we add different number formats as fractional.&lt;br /&gt;
===Keeping a separate input for the numerical response===&lt;br /&gt;
&lt;br /&gt;
# Questions should be explicit for the student.A separate input field for numerical and unit is the most evident way to do this and it is not teacher dependent although, later,  this could be set as an option.&lt;br /&gt;
# Splitting in two fields &lt;br /&gt;
## simplify the coding &lt;br /&gt;
## allow more control on the number format i.e. mandatory exponent format&lt;br /&gt;
## development of other numericals fields&lt;br /&gt;
&lt;br /&gt;
===Adding number format specification to the numerical answer===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A first version is under development with the following design &lt;br /&gt;
# add a &#039;&#039;&#039;locale&#039;&#039;&#039; parameter to the numerical_answer &lt;br /&gt;
# define three initial moodle internal locales &lt;br /&gt;
## &amp;quot;decimal_point_._,&amp;quot;, &lt;br /&gt;
## &amp;quot;decimal_point_.&amp;quot;,&lt;br /&gt;
## &amp;quot;decimal_point_,&amp;quot; &lt;br /&gt;
&lt;br /&gt;
This &#039;&#039;&#039;locale&#039;&#039;&#039; parameter could also be used later to store the official locale names.&lt;br /&gt;
&lt;br /&gt;
It allows the teacher to set different grade to different format&lt;br /&gt;
&lt;br /&gt;
[[File:grading_numerical_format.jpg]]&lt;br /&gt;
Two answers were defined &lt;br /&gt;
* one with &#039;&#039;&#039;locale&#039;&#039;&#039; &amp;quot;decimal_point_,&amp;quot; and fraction = 1 &lt;br /&gt;
* one with &#039;&#039;&#039;locale&#039;&#039;&#039; &amp;quot;decimal_point_.&amp;quot; and fraction = 0.8&lt;br /&gt;
&lt;br /&gt;
P.S. The correct format response display function code is not updated&lt;br /&gt;
&lt;br /&gt;
==How to grade the numerical response ==&lt;br /&gt;
There are 3 elements that should be graded in a numerical question&lt;br /&gt;
&lt;br /&gt;
# the numerical value&lt;br /&gt;
# the unit used in relation to the numeric value&lt;br /&gt;
# the number format used to express the value&lt;br /&gt;
&lt;br /&gt;
===the numerical value===&lt;br /&gt;
&lt;br /&gt;
We need to compare using the tolerance value the numerical answer with the numerical response obtained from &#039;&#039;&#039;locale&#039;&#039;&#039; translated response as typed by the student.&lt;br /&gt;
 This translation process associated by the various &#039;&#039;&#039;locales&#039;&#039;&#039; set &lt;br /&gt;
 by the teacher offer a possible grading of the third grading element&lt;br /&gt;
 i.e. number format.&lt;br /&gt;
&lt;br /&gt;
If there are &#039;&#039;&#039;no unit set with a multiply factor different from 1&#039;&#039;&#039; , the numerical values to test are the different answers.&lt;br /&gt;
&lt;br /&gt;
===grading the combination numerical value : unit ===&lt;br /&gt;
&lt;br /&gt;
However if there are units with factor different from unity, these unit factors generate other numerical values for each answer that when assoicate with the rigth unit, will be identical to of the answers.&lt;br /&gt;
&lt;br /&gt;
i.e.&lt;br /&gt;
answer 15 cm ( unit factor 1 ) &lt;br /&gt;
if expressed as m the good response is 0.15 m&lt;br /&gt;
&lt;br /&gt;
So the possible good numerical responses are 15 or 0.15 &lt;br /&gt;
&lt;br /&gt;
If the student response is 15 or .15 its numerical grade is 100%&lt;br /&gt;
&lt;br /&gt;
He will have a unit penalty if &lt;br /&gt;
# he gave an unrecognized unit although this should not happen as the defined units should be clearly identify in the question text&lt;br /&gt;
# if he does associate the number with the rigth unit&lt;br /&gt;
&lt;br /&gt;
The actual code does not handle differently the 2 cases.&lt;br /&gt;
&lt;br /&gt;
The question::get_matching_answer() and the question:get_matching_answer should be modified to handle &lt;br /&gt;
the unit penalty as it is handle in 2,0.&lt;br /&gt;
&lt;br /&gt;
As these functions should be in question.php the question-&amp;gt;units should be set on initialise_question_instance&lt;br /&gt;
&lt;br /&gt;
So for each answer we need to test for each non unity factor unit.&lt;br /&gt;
&lt;br /&gt;
... [[User:Pierre Pichet|Pierre Pichet]] 01:01, 18 May 2011 (WST)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Setting the answer when creating the question==&lt;br /&gt;
===A proposal===&lt;br /&gt;
The teacher should be able to set&lt;br /&gt;
# the numerical value using the PHP convention&lt;br /&gt;
# the response format , various interface can be used &lt;br /&gt;
# the tolerance&lt;br /&gt;
# the feedback&lt;br /&gt;
&lt;br /&gt;
Here a simplified proposal&lt;br /&gt;
&lt;br /&gt;
[[File:numerical_answer_interface_proposal.jpg]]&lt;br /&gt;
&lt;br /&gt;
===1,9 and 2,0 interface ===&lt;br /&gt;
In Moodle 1,9 and 2,0 in the edit_numerical_form.php, the number enter by the teacher (although student could be allowed to create question, I will use teacher for text clarity) must be conform to the PHP syntax (no thousand separator or space and . as decimal separator. E syntax is allowed.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;code php&amp;gt;                if (!(is_numeric($trimmedanswer) || $trimmedanswer == &#039;*&#039;)) {&lt;br /&gt;
                    $errors[&#039;answer[&#039; . $key . &#039;]&#039;] =&lt;br /&gt;
                            get_string(&#039;answermustbenumberorstar&#039;, &#039;qtype_numerical&#039;);&lt;br /&gt;
                }&lt;br /&gt;
 &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So the teacher must know the PHP specific number syntax.&lt;br /&gt;
&lt;br /&gt;
In the  numerical/questiontype.php    function save_question_options($question) &lt;br /&gt;
there is an additional verification mostly for numerical questions imported through various formats or inside a Cloze numerical multianswer question.&lt;br /&gt;
    &amp;lt;code php&amp;gt;         &lt;br /&gt;
                $answer-&amp;gt;answer = $this-&amp;gt;apply_unit($answerdata, $units);&lt;br /&gt;
                if ($answer-&amp;gt;answer === false) {&lt;br /&gt;
                    $result-&amp;gt;notice = get_string(&#039;invalidnumericanswer&#039;, &#039;quiz&#039;);&lt;br /&gt;
                }&lt;br /&gt;
    &amp;lt;/code&amp;gt;&lt;br /&gt;
the Moodle 2,0 apply_unit&lt;br /&gt;
   &amp;lt;code php&amp;gt; &lt;br /&gt;
    /**&lt;br /&gt;
     * Checks if the $rawresponse has a unit and applys it if appropriate.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $rawresponse  The response string to be converted to a float.&lt;br /&gt;
     * @param array $units         An array with the defined units, where the&lt;br /&gt;
     *                             unit is the key and the multiplier the value.&lt;br /&gt;
     * @return float               The rawresponse with the unit taken into&lt;br /&gt;
     *                             account as a float.&lt;br /&gt;
     */&lt;br /&gt;
    function apply_unit($rawresponse, $units) {&lt;br /&gt;
&lt;br /&gt;
        // Make units more useful&lt;br /&gt;
        $tmpunits = array();&lt;br /&gt;
        foreach ($units as $unit) {&lt;br /&gt;
            $tmpunits[$unit-&amp;gt;unit] = $unit-&amp;gt;multiplier;&lt;br /&gt;
        }&lt;br /&gt;
        // remove spaces and normalise decimal places.&lt;br /&gt;
        $rawresponse = trim($rawresponse) ;&lt;br /&gt;
        $search  = array(&#039; &#039;, &#039;,&#039;);&lt;br /&gt;
        // test if a . is present or there are multiple , (i.e. 2,456,789 ) so that we don&#039;t need spaces and ,&lt;br /&gt;
        if ( strpos($rawresponse,&#039;.&#039; ) !== false || substr_count($rawresponse,&#039;,&#039;) &amp;gt; 1 ) {&lt;br /&gt;
            $replace = array(&#039;&#039;, &#039;&#039;);&lt;br /&gt;
        }else { // remove spaces and normalise , to a . .&lt;br /&gt;
            $replace = array(&#039;&#039;, &#039;.&#039;);&lt;br /&gt;
        }&lt;br /&gt;
        $rawresponse = str_replace($search, $replace, $rawresponse);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        // Apply any unit that is present.&lt;br /&gt;
        if (ereg(&#039;^([+-]?([0-9]+(\\.[0-9]*)?|\\.[0-9]+)([eE][-+]?[0-9]+)?)([^0-9].*)?$&#039;,&lt;br /&gt;
                $rawresponse, $responseparts)) {&lt;br /&gt;
                echo&amp;quot;&amp;lt;p&amp;gt; responseparts &amp;lt;pre&amp;gt;&amp;quot;;print_r($responseparts) ;echo&amp;quot;&amp;lt;/pre&amp;gt;&amp;lt;/p&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
            if (!empty($responseparts[5])) {&lt;br /&gt;
&lt;br /&gt;
                if (isset($tmpunits[$responseparts[5]])) {&lt;br /&gt;
                    // Valid number with unit.&lt;br /&gt;
                    return (float)$responseparts[1] / $tmpunits[$responseparts[5]];&lt;br /&gt;
                } else {&lt;br /&gt;
                    // Valid number with invalid unit. Must be wrong.&lt;br /&gt;
                    return false;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
            } else {&lt;br /&gt;
                // Valid number without unit.&lt;br /&gt;
                return (float)$responseparts[1];&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        // Invalid number. Must be wrong.&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
 &amp;lt;/code&amp;gt;&lt;br /&gt;
The 2,0 apply_unit allows more number formats than the test in the editing form. &lt;br /&gt;
&lt;br /&gt;
* regular numbers  13500.67 : 13 500.67 : 13500,67: 13 500,67&lt;br /&gt;
&lt;br /&gt;
* if you use , as thousand separator *always* put the decimal . as in 13,500.67 : 13,500.&lt;br /&gt;
 &lt;br /&gt;
* for exponent form, say 1.350067 * 10&amp;lt;sup&amp;gt;4&amp;lt;/sup&amp;gt;, use 1.350067 E4 : 1.350067 E04 &#039;;&lt;br /&gt;
&lt;br /&gt;
The 1,9 apply_unit is more restrictive as it does not support , as decimal separator.&lt;br /&gt;
&lt;br /&gt;
More formats were allowed in 2,0 as the main objective in a numerical question is the numerical value.&lt;br /&gt;
More about this further in the page (todo)&lt;br /&gt;
&lt;br /&gt;
==Converting number in a string to a double or float variable==&lt;br /&gt;
&lt;br /&gt;
The answer is being stored in a TEXT database field or in a string in import-export files.&lt;br /&gt;
&lt;br /&gt;
However in numerical questiontype code it is used a numeric PHP parameter (float or double).&lt;br /&gt;
From http://ca2.php.net/manual/en/language.types.string.php#language.types.string.conversion&lt;br /&gt;
&lt;br /&gt;
===String conversion to numbers===&lt;br /&gt;
&lt;br /&gt;
When a string is evaluated in a numeric context, the resulting value and type are determined as follows.&lt;br /&gt;
&lt;br /&gt;
If the string *does not contain* any of the characters &#039;.&#039;, &#039;e&#039;, or &#039;E&#039; and the numeric value fits into integer type limits (as defined by PHP_INT_MAX), the string will be evaluated as an integer. In all other cases it will be evaluated as a float.&lt;br /&gt;
&lt;br /&gt;
The value is given by the initial portion of the string. If the string starts with valid numeric data, this will be the value used. Otherwise, the value will be 0 (zero). Valid numeric data is an optional sign, followed by one or more digits (optionally containing a decimal point), followed by an optional exponent. The exponent is an &#039;e&#039; or &#039;E&#039; followed by one or more digits.&lt;br /&gt;
&lt;br /&gt;
For more information on this conversion, see the Unix manual page for strtod(3).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Unix manual page for strtod====&lt;br /&gt;
http://compute.cnr.berkeley.edu/cgi-bin/man-cgi?strtod+3 &lt;br /&gt;
DESCRIPTION&lt;br /&gt;
&lt;br /&gt;
     The strtod(), strtof(), and strtold() functions convert  the&lt;br /&gt;
     initial  portion of the string pointed to by nptr to double,&lt;br /&gt;
     float, and long double representation,  respectively.  First&lt;br /&gt;
     they decompose the input string into three parts:&lt;br /&gt;
     1.  An initial,  possibly  empty,  sequence  of  white-space&lt;br /&gt;
         characters (as specified by isspace(3C))&lt;br /&gt;
     2.  A subject sequence interpreted as a floating-point  con-&lt;br /&gt;
         stant or representing infinity or NaN&lt;br /&gt;
     3.  A final string of one or more  unrecognized  characters,&lt;br /&gt;
         including the terminating null byte of the input string.&lt;br /&gt;
     Then they attempt to  convert  the  subject  sequence  to  a&lt;br /&gt;
     floating-point number, and return the result.&lt;br /&gt;
     The expected form of the subject  sequence  is  an  optional&lt;br /&gt;
     plus or minus sign, then one of the following:&lt;br /&gt;
       o  A non-empty sequence of digits optionally containing  &#039;&#039;&#039;a&lt;br /&gt;
          radix character&#039;&#039;&#039;, then an optional exponent part&lt;br /&gt;
       o  A 0x or 0X, then a non-empty  sequence  of  hexadecimal&lt;br /&gt;
          digits optionally containing a radix character, then an&lt;br /&gt;
          optional binary exponent part&lt;br /&gt;
       o  One of INF or INFINITY, ignoring case&lt;br /&gt;
...&lt;br /&gt;
     The &#039;&#039;&#039;radix character&#039;&#039;&#039;  is  defined  in  the  program&#039;s  locale&lt;br /&gt;
     (category  LC_NUMERIC).  In the POSIX locale, or in a locale&lt;br /&gt;
     where the &#039;&#039;&#039;radix character&#039;&#039;&#039; is not defined, the &#039;&#039;&#039;radix  charac-&lt;br /&gt;
     ter&#039;&#039;&#039; defaults to a period (&#039;.&#039;).&lt;br /&gt;
So if the locale LC_NUMERIC i.e.&lt;br /&gt;
&amp;lt;code php &amp;gt;&lt;br /&gt;
Array&lt;br /&gt;
(&lt;br /&gt;
    [decimal_point] =&amp;gt; .&lt;br /&gt;
    [thousands_sep] =&amp;gt; &lt;br /&gt;
    [int_curr_symbol] =&amp;gt; &lt;br /&gt;
    [currency_symbol] =&amp;gt; &lt;br /&gt;
    [mon_decimal_point] =&amp;gt; &lt;br /&gt;
    [mon_thousands_sep] =&amp;gt; &lt;br /&gt;
    [positive_sign] =&amp;gt; &lt;br /&gt;
    [negative_sign] =&amp;gt; &lt;br /&gt;
    [int_frac_digits] =&amp;gt; 127&lt;br /&gt;
    [frac_digits] =&amp;gt; 127&lt;br /&gt;
    [p_cs_precedes] =&amp;gt; 127&lt;br /&gt;
    [p_sep_by_space] =&amp;gt; 127&lt;br /&gt;
    [n_cs_precedes] =&amp;gt; 127&lt;br /&gt;
    [n_sep_by_space] =&amp;gt; 127&lt;br /&gt;
    [p_sign_posn] =&amp;gt; 127&lt;br /&gt;
    [n_sign_posn] =&amp;gt; 127&lt;br /&gt;
    [grouping] =&amp;gt; Array&lt;br /&gt;
        (&lt;br /&gt;
        )&lt;br /&gt;
&lt;br /&gt;
    [mon_grouping] =&amp;gt; Array&lt;br /&gt;
        (&lt;br /&gt;
        )&lt;br /&gt;
&lt;br /&gt;
 )&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
define &#039;&#039;&#039;decimal_point&#039;&#039;&#039; not as . as here but as , then 1,234.56 will be recognized as 1,234 i.e. smaller than 2 although the number written is greater than 1000. &lt;br /&gt;
==== PHP 5.36 zend_strtod()====&lt;br /&gt;
However in PHP 5.3.6 strtod() is replaced by zend_strtod()&lt;br /&gt;
&amp;lt;code c &amp;gt;&lt;br /&gt;
 ZEND_API double zend_strtod (CONST char *s00, char **se)&lt;br /&gt;
 {&lt;br /&gt;
	int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign,&lt;br /&gt;
		e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign;&lt;br /&gt;
	CONST char *s, *s0, *s1;&lt;br /&gt;
	volatile double aadj, aadj1, adj;&lt;br /&gt;
	volatile _double rv, rv0;&lt;br /&gt;
	Long L;&lt;br /&gt;
	ULong y, z;&lt;br /&gt;
	Bigint *bb, *bb1, *bd, *bd0, *bs, *delta, *tmp;&lt;br /&gt;
	double result;&lt;br /&gt;
&lt;br /&gt;
	&#039;&#039;&#039;CONST char decimal_point = &#039;.&#039;;&#039;&#039;&#039;&lt;br /&gt;
   ...&lt;br /&gt;
			z = 10*z + c - &#039;0&#039;;&lt;br /&gt;
	nd0 = nd;&lt;br /&gt;
	if (c == decimal_point) {&lt;br /&gt;
		c = *++s;&lt;br /&gt;
		if (!nd) {&lt;br /&gt;
			for(; c == &#039;0&#039;; c = *++s)&lt;br /&gt;
				nz++;&lt;br /&gt;
			if (c &amp;gt; &#039;0&#039; &amp;amp;&amp;amp; c &amp;lt;= &#039;9&#039;) {&lt;br /&gt;
				s0 = s;&lt;br /&gt;
				nf += nz;&lt;br /&gt;
				nz = 0;&lt;br /&gt;
				goto have_dig;&lt;br /&gt;
			}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt; &lt;br /&gt;
 &lt;br /&gt;
&#039;&#039;&#039;So in PHP 5.3.6 the zend_strtod() ALWAYS use . as decimal_point&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Other functions allow the user to define the decimal_point or use the locale defined decimal_point.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
=== is_numeric()===&lt;br /&gt;
&amp;lt;code c&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Checks whether the string &amp;quot;str&amp;quot; with length &amp;quot;length&amp;quot; is numeric. The value&lt;br /&gt;
 * of allow_errors determines whether it&#039;s required to be entirely numeric, or&lt;br /&gt;
 * just its prefix. Leading whitespace is allowed.&lt;br /&gt;
 *&lt;br /&gt;
 * The function returns 0 if the string did not contain a valid number; IS_LONG&lt;br /&gt;
 * if it contained a number that fits within the range of a long; or IS_DOUBLE&lt;br /&gt;
 * if the number was out of long range or contained a decimal point/exponent.&lt;br /&gt;
 * The number&#039;s value is returned into the respective pointer, *lval or *dval,&lt;br /&gt;
 * if that pointer is not NULL.&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
static inline zend_uchar is_numeric_string(const char *str, int length, long *lval, double *dval, int allow_errors)&lt;br /&gt;
{&lt;br /&gt;
	const char *ptr;&lt;br /&gt;
	int base = 10, digits = 0, dp_or_e = 0;&lt;br /&gt;
	double local_dval;&lt;br /&gt;
	zend_uchar type;&lt;br /&gt;
&lt;br /&gt;
	if (!length) {&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/* Skip any whitespace&lt;br /&gt;
	 * This is much faster than the isspace() function */&lt;br /&gt;
	while (*str == &#039; &#039; || *str == &#039;\t&#039; || *str == &#039;\n&#039; || *str == &#039;\r&#039; || *str == &#039;\v&#039; || *str == &#039;\f&#039;) {&lt;br /&gt;
		str++;&lt;br /&gt;
		length--;&lt;br /&gt;
	}&lt;br /&gt;
	ptr = str;&lt;br /&gt;
&lt;br /&gt;
	if (*ptr == &#039;-&#039; || *ptr == &#039;+&#039;) {&lt;br /&gt;
		ptr++;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	if (ZEND_IS_DIGIT(*ptr)) {&lt;br /&gt;
		/* Handle hex numbers&lt;br /&gt;
		 * str is used instead of ptr to disallow signs and keep old behavior */&lt;br /&gt;
		if (length &amp;gt; 2 &amp;amp;&amp;amp; *str == &#039;0&#039; &amp;amp;&amp;amp; (str[1] == &#039;x&#039; || str[1] == &#039;X&#039;)) {&lt;br /&gt;
			base = 16;&lt;br /&gt;
			ptr += 2;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		/* Skip any leading 0s */&lt;br /&gt;
		while (*ptr == &#039;0&#039;) {&lt;br /&gt;
			ptr++;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		/* Count the number of digits. If a decimal point/exponent is found,&lt;br /&gt;
		 * it&#039;s a double. Otherwise, if there&#039;s a dval or no need to check for&lt;br /&gt;
		 * a full match, stop when there are too many digits for a long */&lt;br /&gt;
		for (type = IS_LONG; !(digits &amp;gt;= MAX_LENGTH_OF_LONG &amp;amp;&amp;amp; (dval || allow_errors == 1)); digits++, ptr++) {&lt;br /&gt;
check_digits:&lt;br /&gt;
			if (ZEND_IS_DIGIT(*ptr) || (base == 16 &amp;amp;&amp;amp; ZEND_IS_XDIGIT(*ptr))) {&lt;br /&gt;
				continue;&lt;br /&gt;
			} else if (base == 10) {&lt;br /&gt;
				if (*ptr == &#039;.&#039; &amp;amp;&amp;amp; dp_or_e &amp;lt; 1) {&lt;br /&gt;
					goto process_double;&lt;br /&gt;
				} else if ((*ptr == &#039;e&#039; || *ptr == &#039;E&#039;) &amp;amp;&amp;amp; dp_or_e &amp;lt; 2) {&lt;br /&gt;
					const char *e = ptr + 1;&lt;br /&gt;
&lt;br /&gt;
					if (*e == &#039;-&#039; || *e == &#039;+&#039;) {&lt;br /&gt;
						ptr = e++;&lt;br /&gt;
					}&lt;br /&gt;
					if (ZEND_IS_DIGIT(*e)) {&lt;br /&gt;
						goto process_double;&lt;br /&gt;
					}&lt;br /&gt;
				}&lt;br /&gt;
			}&lt;br /&gt;
&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The decimal point is hard written in the code &#039;&#039;&#039;if (*ptr == &#039;.&#039; &amp;amp;&amp;amp; dp_or_e &amp;lt; 1)&#039;&#039;&#039;, so the test will not be locale dependent.&lt;br /&gt;
&lt;br /&gt;
Note that this function allows hexadecimal written numbers so in numerical we need another function (like apply_unit() to only use decimals.&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_formats&amp;diff=37136</id>
		<title>Question Engine 2:Numerical formats</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_formats&amp;diff=37136"/>
		<updated>2013-01-09T17:15:13Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: /* Numbers */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The Question Engine 2 structure allows implementation of new features for numerical question types ( numerical and calculated).&lt;br /&gt;
&lt;br /&gt;
This page describes a possible implementation and its rationale.&lt;br /&gt;
&lt;br /&gt;
The text should be readed as a personal summary of the work in progress and not as a textbook on computer language and real numbers representation.&lt;br /&gt;
&lt;br /&gt;
It is related to an initial quiz forum discussion &lt;br /&gt;
http://moodle.org/mod/forum/discuss.php?d=172211#p755927&lt;br /&gt;
&lt;br /&gt;
Please put your comments on the forum.&lt;br /&gt;
http://moodle.org/mod/forum/discuss.php?d=174387&lt;br /&gt;
&lt;br /&gt;
See also http://tracker.moodle.org/browse/MDL-2736&lt;br /&gt;
&lt;br /&gt;
See also [[Question Engine 2:Numerical questions]]&lt;br /&gt;
&lt;br /&gt;
==Numerical question grading ==&lt;br /&gt;
&lt;br /&gt;
There are 3 elements that can be graded in a numerical question&lt;br /&gt;
# the numeric value&lt;br /&gt;
# the unit used in relation to the numeric value&lt;br /&gt;
# the number format used to express the value&lt;br /&gt;
&lt;br /&gt;
1 and 2 are addressed in Moodle 2,0 for questions created from edit_numerical_form.php.&lt;br /&gt;
 &lt;br /&gt;
3 can give a 0 grade if the student does not use one of the number formats allowed but there is no specific grading designed as the unit penalty since Moodle 2,0.&lt;br /&gt;
&lt;br /&gt;
==How to design the code flow for grading a numerical question==&lt;br /&gt;
&lt;br /&gt;
Ideally we should be able to sinulate the teacher grading approach which is about the following&lt;br /&gt;
# Find the numerical characters (+-123456...) and translate them in a number following locale numbering style(s) allowed to the students response. To be fair the style should be known to the students if they are different from their usual langage number style.&lt;br /&gt;
# Compare the translated number to the numerical good answer or the equivalent if they are expressed in authorized units allowed.&lt;br /&gt;
# Identify the units part of the response and verify if it is well written and one of the in authorized units allowed&lt;br /&gt;
# Verify if the unit is the correct one to use so that the response express the numerical value of the answer.&lt;br /&gt;
&lt;br /&gt;
===Identify the number in the response===&lt;br /&gt;
&lt;br /&gt;
The more variant ways you allow in expressing the numerical value, the more complex will be the decoding process.&lt;br /&gt;
&lt;br /&gt;
When a teacher decode a student response, he can pinpoint errors in the number writing and exptract the most plausible numerical value from student response and grade separately the numerical value from the errors in the number syntax using a more or less complex grading approach.&lt;br /&gt;
&lt;br /&gt;
===Compare the response numerical value to answer numerical value===&lt;br /&gt;
This comparison is easily done in computer code and the moodle code allow to set different tolerance and can even the teacher can even set another answer related to a common error (i.e. 2 * ) and give a specific grade.&lt;br /&gt;
&lt;br /&gt;
===Identify the unit in the response===&lt;br /&gt;
Here the actual moodle code is quite limited as are limited the unit syntax that can be used.&lt;br /&gt;
Just think of expressing a surface in  squared mm&lt;br /&gt;
This is why the multiple choice variant was added in 2,0 as the teacher could set complex math formula in the question text that the student could choose.&lt;br /&gt;
&lt;br /&gt;
The numerical syntax is not the main objective of the numerical question and given the limits of the pattern recognition performance of the code, the use of two input fields (number and unit) to help the student to express the two part of the response as it helps moodle to identify them correctly. &lt;br /&gt;
&lt;br /&gt;
It allows also the &lt;br /&gt;
# the use of more variant forms of expressing the numerical values ( fractions, time, degress)&lt;br /&gt;
# development of specific tool to express complex unities.&lt;br /&gt;
&lt;br /&gt;
===The events in the decoding steps===&lt;br /&gt;
Given the new opportunities of the new engine qtype_numerical_walkthrough that extends qbehaviour_walkthrough, the code should reflect the different results obtained in the response analysis.&lt;br /&gt;
&lt;br /&gt;
This is not an easy task that will complexify each time we will allow more flexibility in number and units formats.&lt;br /&gt;
&lt;br /&gt;
====Identify the number in the response====&lt;br /&gt;
Find the numerical characters (+-123456...) and translate them in a number following locale numbering style(s) allowed to the students response. To be fair the style should be known to the students if it&#039;s  different from their current language usage ( help icon).&lt;br /&gt;
&lt;br /&gt;
Given the identified response input element , the code can detect that there are additional characters that are not used in the extracted number but this could result from accidental typing error but most often from badly written number which most will have its own penalty when grading for the numerical value.&lt;br /&gt;
&lt;br /&gt;
====Identify the unit in the response====&lt;br /&gt;
Identify the units part of the response. &lt;br /&gt;
There is no easy syntax analysis to detect syntax errors.&lt;br /&gt;
# field empty&lt;br /&gt;
# the correspondance with one units set in the question can be (and is)done later.&lt;br /&gt;
&lt;br /&gt;
====Compare the response numerical value to answer numerical value using the units factor====&lt;br /&gt;
Compare the translated number to the numerical good answer or the equivalent if they are expressed in authorized units allowed.&lt;br /&gt;
&lt;br /&gt;
This is done with the result that report the grade and the unit used to set the grade.&lt;br /&gt;
&lt;br /&gt;
====Verify if the unit from the response is the one used in setting the numerical grade====&lt;br /&gt;
Verify &lt;br /&gt;
# if the unit is well written and one of the in authorized units allowed.&lt;br /&gt;
# if the unit is the correct one to use so that the response express the numerical value of the answer.&lt;br /&gt;
&lt;br /&gt;
The unit_penalty reflects this step but a different message should be given following the 2 cases although the second one cannot happen with multichoice option.&lt;br /&gt;
&lt;br /&gt;
==The different number formats==&lt;br /&gt;
Numerical quantity can be expresed as&lt;br /&gt;
#  Integer without decsep and with or without thousandseps  (many combinations related to number locale)  as 1234  1 234&lt;br /&gt;
#  Decimal with a decsep ( either , or . ) and with or without thousandseps (many combinations related to number locale)  as 1234.456  1 234,456 &lt;br /&gt;
#  Exponent form with a decsep ( either , or . ) and without  thousandseps ? as 1.23456 E3&lt;br /&gt;
#  Fractional form the dessep is &#039; &#039;  and without  thousandseps  as 1234 456/1000&lt;br /&gt;
#  Angles as degree minute second&lt;br /&gt;
#  Time as hour:minute:second&lt;br /&gt;
# Etc.&lt;br /&gt;
&lt;br /&gt;
The international locale parameters defined are mainly related to the decimal form and constitue a long list as they are related mostly to the language.&lt;br /&gt;
&lt;br /&gt;
I propose that we do not define our number parameters to these locale although in the help we could relate the decsep and tousand to the international locales.&lt;br /&gt;
&lt;br /&gt;
The 2,0 formats allowed simultaneously by apply_unit() function are&lt;br /&gt;
&lt;br /&gt;
#  Integer without decsep and with or without thousandseps  (many combinations related to number locale)  as 1234  1 234&lt;br /&gt;
#  Decimal with a decsep ( either , or . ) and with or without thousandseps ( &#039; &#039; or &#039;,&#039; if decsep == &#039;.&#039; )  as 1234.456  1 234,456 &lt;br /&gt;
#  Exponent form with a decsep ( either , or . ) and with  thousandseps  ( &#039; &#039; or &#039;,&#039; if decsep == &#039;.&#039; ) as 1.23456 E3&lt;br /&gt;
&lt;br /&gt;
in 1,9 the decsep &#039;,&#039; was not allowed&lt;br /&gt;
&lt;br /&gt;
==Identify the number in the response==&lt;br /&gt;
&lt;br /&gt;
The function apply_value($response,$unit) used to identify the number unit combination and retrun the numerical value for grading as evolved in the different moodle version allowing more complete number analysis but without a significant output to apply a number format penalty other than 0 or 1 value.&lt;br /&gt;
&lt;br /&gt;
Grading the different formats can be applied either at the &lt;br /&gt;
=== the question level===&lt;br /&gt;
 using a more complex number analysis with an output that can be used to apply a number format penalty&lt;br /&gt;
&lt;br /&gt;
===  the answer level.===&lt;br /&gt;
As grading is done at the answer level adding an additional element to the answer (i.e. tolerance) was first explored as a solution.see lower in this page https://docs.moodle.org/en/Development:Question_Engine_2:Numerical_formats#How_to_grade_a_numerical_response_format&lt;br /&gt;
However this solution implies that the user set the number format analysis pattern to apply.&lt;br /&gt;
&lt;br /&gt;
So improving the flexibility of the number analysis at the question level appers as a better solution&lt;br /&gt;
&lt;br /&gt;
==Improving the number analysis at the question level==&lt;br /&gt;
&lt;br /&gt;
To apply a more complete number analysis we need at least the following parameters that should be stored in a new database table.&lt;br /&gt;
# usual id and question&lt;br /&gt;
# the name of the analysis (either specific as &#039;decimal&#039; or a mixed combination )&lt;br /&gt;
# the order in this variant in the analysis and the grade associated with the result as&lt;br /&gt;
## decsep = . with thousand = ,   and grade 100% of the given answer fraction&lt;br /&gt;
## decsep = . with thousand = &#039; &#039;  and grade 90% of the given answer fraction&lt;br /&gt;
## decsep all and and grade 80% of the given answer fraction&lt;br /&gt;
# params used in this numerical variant most often decsep and thousands but could be also the exponential form (alloed or not) or new ones like / for fraction.&lt;br /&gt;
&lt;br /&gt;
The field &#039;name&#039; should be related to a  number class that can handle the necessary grading, saving and retrieving steps.&lt;br /&gt;
&lt;br /&gt;
We need to define these number classes before going further [[User:Pierre Pichet|Pierre Pichet]] 15:30, 31 May 2011 (WST)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 if ($oldversion &amp;lt; 2011052200 ) { //New version in version.php&lt;br /&gt;
&lt;br /&gt;
    /// Define table question_numerical_options to be created&lt;br /&gt;
        $table = new xmldb_table(&#039;question_numerical_formats&#039;);&lt;br /&gt;
&lt;br /&gt;
    /// Adding fields to table question_numerical_formats &lt;br /&gt;
       $table-&amp;gt;add_field(&#039;id&#039;, XMLDB_TYPE_INTEGER, &#039;10&#039;, XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);&lt;br /&gt;
        $table-&amp;gt;add_field(&#039;question&#039;, XMLDB_TYPE_INTEGER, &#039;10&#039;, XMLDB_UNSIGNED, XMLDB_NOTNULL, null, &#039;0&#039;);&lt;br /&gt;
        $table-&amp;gt;add_field(&#039;name&#039;, XMLDB_TYPE_TEXT, &#039;small&#039;, null, null, null, null);&lt;br /&gt;
        $table-&amp;gt;add_field(&#039;order&#039;, XMLDB_TYPE_INTEGER, &#039;10&#039;, XMLDB_UNSIGNED, XMLDB_NOTNULL, null, &#039;0&#039;);&lt;br /&gt;
        $table-&amp;gt;add_field(&#039;grade&#039;, XMLDB_TYPE_NUMBER, &#039;12, 7&#039;, XMLDB_UNSIGNED, XMLDB_NOTNULL, null, &#039;0&#039;);&lt;br /&gt;
        $table-&amp;gt;add_field(&#039;params&#039;, XMLDB_TYPE_TEXT, &#039;small&#039;, null, null, null, null);&lt;br /&gt;
&lt;br /&gt;
    /// Adding keys to table question_numerical_formats&lt;br /&gt;
        $table-&amp;gt;add_key(&#039;primary&#039;, XMLDB_KEY_PRIMARY, array(&#039;id&#039;));&lt;br /&gt;
        $table-&amp;gt;add_key(&#039;question&#039;, XMLDB_KEY_FOREIGN, array(&#039;question&#039;), &#039;question&#039;, array(&#039;id&#039;));&lt;br /&gt;
    /// Conditionally launch create table for question_calculated_options&lt;br /&gt;
        if (!$dbman-&amp;gt;table_exists($table)) {&lt;br /&gt;
            // $dbman-&amp;gt;create_table doesnt return a result, we just have to trust it&lt;br /&gt;
            $dbman-&amp;gt;create_table($table);&lt;br /&gt;
        }&lt;br /&gt;
        upgrade_plugin_savepoint(true, 2011052200, &#039;qtype&#039;, &#039;numerical&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The info about the different parameters ( like the official locales decsep amd thousandsep ) and analysis coding could be stored in an additional numerical/number_analysis.php file&lt;br /&gt;
&lt;br /&gt;
 When sufficiently developped, this number analysis code should become a question engine function or type i.e graded as ...&lt;br /&gt;
&lt;br /&gt;
==Implementing in 2,1 release==&lt;br /&gt;
&lt;br /&gt;
Given the delays we need to set the minimal changes that will set the necessary code structure for allowing the various aspects discussed in the upper part of this page even if as a first version we do not all of them.&lt;br /&gt;
===Locale ( i.e decsep) is defined at the question level not at the site level===&lt;br /&gt;
We need &lt;br /&gt;
# set the locale parameters in a question related database table (i.e. as unit are)&lt;br /&gt;
## create the database structure&lt;br /&gt;
## the save and read functions&lt;br /&gt;
## create the edit_numererical_fomr code to set the paramters at the question level&lt;br /&gt;
## eliminate the construct functions that defined the locale default as site locale default&lt;br /&gt;
## set the apply_value code to multiple decseps and or thousandseps&lt;br /&gt;
## implement a minimal numerical format grading&lt;br /&gt;
### a first choice as either . or , decsep grade 100%&lt;br /&gt;
### a second choice as the other decsep  graded as desired (0-100%)  &lt;br /&gt;
## default the pretty number decsep to PHP standard i.e. &#039;.&#039; or the first choice . &lt;br /&gt;
&lt;br /&gt;
===Units===&lt;br /&gt;
&lt;br /&gt;
As the unit uses already a specific input field in 2,0 , we should continue this in 2,1 as in the future this will allow us maximum flexibility.&lt;br /&gt;
&lt;br /&gt;
Technically, we should use the coding structure developed by Tim in the multianswer renderer to continue the use of multichoice regular display as it allows HTML and even Latex rendering.&lt;br /&gt;
&lt;br /&gt;
We should implement unit grading as done in 2,0 i.e. the response numerical value is tested against the answer value using all defined units. &lt;br /&gt;
&lt;br /&gt;
We need to create the corresponding response states.&lt;br /&gt;
&lt;br /&gt;
==Numbers==&lt;br /&gt;
from http://en.wikipedia.org/wiki/Number&lt;br /&gt;
&lt;br /&gt;
The real numbers include all of the measuring numbers. Real numbers are usually written using [[decimal]] numerals, in which a decimal point is placed to the right of the digit with place value one. Each digit to the right of the decimal point has a place value one-tenth of the place value of the digit to its left.  &lt;br /&gt;
&lt;br /&gt;
Thus&lt;br /&gt;
&lt;br /&gt;
123.456&lt;br /&gt;
&lt;br /&gt;
represents 1 hundred, 2 tens, 3 ones, 4 tenths, 5 hundredths, and 6 thousandths.&lt;br /&gt;
&lt;br /&gt;
In the US and UK and a number of other countries, the decimal point is represented by a period, whereas in continental Europe and certain other countries the decimal point is represented by a comma. &lt;br /&gt;
&lt;br /&gt;
Zero is often written as 0.0 when it must be treated as a real number rather than an integer. &lt;br /&gt;
&lt;br /&gt;
In the US and UK a number between −1 and 1 is always written with a leading zero to emphasize the decimal. &lt;br /&gt;
&lt;br /&gt;
Negative real numbers are written with a preceding minus sign: -123.456.&lt;br /&gt;
&lt;br /&gt;
Every rational number is also a real number. It is not the case, however, that every real number is rational. If a real number cannot be written as a fraction of two integers, it is called irrational number. &lt;br /&gt;
&lt;br /&gt;
A decimal that can be written as a fraction either ends (terminates) or forever repeating decimal, because it is the answer to a problem in division. &lt;br /&gt;
&lt;br /&gt;
Thus the real number 0.5 can be written as 1/2 and the real number 0.333... (forever repeating threes, otherwise written 0.overline|3}}) can be written as 1/3.  On the other hand, the real number π , the ratio of the circumference of any circle to its diameter, is&lt;br /&gt;
pi = 3.14159265358979&lt;br /&gt;
Since the decimal neither ends nor forever repeats, it cannot be written as a fraction, and is an example of an irrational number. &lt;br /&gt;
&lt;br /&gt;
Thus 1.0 and 0.999... are two different decimal numerals representing the natural number 1.&lt;br /&gt;
&lt;br /&gt;
There are infinitely many other ways of representing the number 1, for example 2/2, 3/3, 1.00, 1.000, and so on.&lt;br /&gt;
&lt;br /&gt;
Every real number is either rational or irrational. Every real number corresponds to a point on the number line. &lt;br /&gt;
&lt;br /&gt;
When a real number represents a measurement, there is always a margin of error. This is often indicated by rounding or truncate|truncating a decimal, so that digits that suggest a greater accuracy than the measurement itself are removed.  The remaining digits are called significant digits. &lt;br /&gt;
&lt;br /&gt;
For example, measurements with a ruler can seldom be made without a margin of error of at least 0.01 meters. If the sides of a rectangle are measured as 1.23 meters and 4.56 meters, then multiplication gives an area for the rectangle of 5.6088 square meters. Since only the first two digits after the decimal place are significant, this is usually rounded to 5.61.&lt;br /&gt;
&lt;br /&gt;
see also http://en.wikipedia.org/wiki/Non-breaking_space&lt;br /&gt;
&lt;br /&gt;
==Designing a number format penalty==&lt;br /&gt;
&lt;br /&gt;
We have already 2 ways to grade the student response available in the edit_numerical_form.php. i.e. &lt;br /&gt;
* the answer-tolerance combination&lt;br /&gt;
* the detailed unit grading &lt;br /&gt;
&lt;br /&gt;
We need flexibility to take in account that number format can vary even at a same location i.e. in Canada there are two locales as there are two official languages (french and english).&lt;br /&gt;
&lt;br /&gt;
Teacher sometimes ask for specific number formats as fraction that cannot be allowed simultanuously to other grading.&lt;br /&gt;
&lt;br /&gt;
The most universal solution is to associate a grade to a specific answer numerical format as the tolerance is used.&lt;br /&gt;
&lt;br /&gt;
For example in calculated the tolerance can be set as relative or absolute.&lt;br /&gt;
&lt;br /&gt;
So my proposal is to add the number format as a new answer parameter.&lt;br /&gt;
&lt;br /&gt;
To an official locales list of available formats we could add &lt;br /&gt;
* specific Moodle formats as the one used for 1,9 2,0 , &lt;br /&gt;
* a fraction format, &lt;br /&gt;
* time format, &lt;br /&gt;
* degree,  minute, second &lt;br /&gt;
* etc.&lt;br /&gt;
==Numbers as written by human and readed by computer language== &lt;br /&gt;
&lt;br /&gt;
The main feature of numerical question type is to ask the student to give a numerical answer i.e. a number.&lt;br /&gt;
Most often this means a numerical value that is not an integer ( dates are a current example of integer value response) but a real number which value is expressed most often as a decimal number i.e 1.234 .&lt;br /&gt;
&lt;br /&gt;
Computer languages ( i.e PHP used in Moodle) store real numbers in a different way than human do (decimal part and exponent similar to 1.234 E00) and humans do not expressed real nmumbers in an universal format.&lt;br /&gt;
&lt;br /&gt;
 The separator between the unit and the decimal fraction is often either a . or a ,  &lt;br /&gt;
 1.234   1,234&lt;br /&gt;
&lt;br /&gt;
Furthermore to help reading large numbers, most language add another separator for thousands often space or , if it is not used already as unit separator.&lt;br /&gt;
 123 456.78     123,456.78   123 456,78 &lt;br /&gt;
&lt;br /&gt;
PHP as a computer language use space to separate the language components so cannot use space as a thousand separator.&lt;br /&gt;
&lt;br /&gt;
, is also used to separate variables so PHP use a simpler syntax 123456.78.&lt;br /&gt;
&lt;br /&gt;
As this is stored in the computer as 2 parts (number and exponent).&lt;br /&gt;
 1.2345678+E05 will be a structure that is well recognized by a computer language as PHP.&lt;br /&gt;
&lt;br /&gt;
==Computers as dummy readers of human number writing==&lt;br /&gt;
&lt;br /&gt;
Ordinary peoples know from their experiences with  hand calculators or even sophisticated spreadsheets that computer are more or less &amp;quot;stupid&amp;quot; to recognized correctly the numbers or numerical values typed by humans.&lt;br /&gt;
&lt;br /&gt;
We as human need to know the number style that the computer will recognize as this can vary among the different computer usages.&lt;br /&gt;
&lt;br /&gt;
Typing a number in your on-line tax report is not the same as typing a number inside a complex math formula.&lt;br /&gt;
Tax reports will handle well various number formats i.e. &lt;br /&gt;
&lt;br /&gt;
# with or without the $ sign,  &lt;br /&gt;
# with or without the space or , as thousand separator&lt;br /&gt;
# will not accept exponential formating as $ 1e6 etc,&lt;br /&gt;
&lt;br /&gt;
However when writing a mathematical formula you cannot &lt;br /&gt;
# cannot put units i.e $ &lt;br /&gt;
#  space or , as thousands sep in numbers etc.&lt;br /&gt;
&lt;br /&gt;
Even if you type a number in a format, the computer could display it in another format.&lt;br /&gt;
&lt;br /&gt;
You type in a spreadsheet  =1e-3&lt;br /&gt;
 &lt;br /&gt;
On return the display could be 0.001 &lt;br /&gt;
&lt;br /&gt;
 &#039;&#039;&#039;Number formats can be different following their usage : i.e tax reports and mathematical formula&#039;&#039;&#039;&lt;br /&gt;
 &lt;br /&gt;
 &#039;&#039;&#039;Humans have to learn which number format to use in a  given computer software case&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==Moodle 1,9 and 2,0 users and numbers  in a numerical and calculated question types ==&lt;br /&gt;
There are two main cases &lt;br /&gt;
=== The teacher setting the answer===&lt;br /&gt;
 &lt;br /&gt;
:in a numerical question answer&lt;br /&gt;
&lt;br /&gt;
::&#039;&#039;&#039;numerical questiontype IS NOT a shortanswer questiontype&#039;&#039;&#039; &lt;br /&gt;
:: At first sight we think that the number should be typed as the response that the student will type to have a full grade.&lt;br /&gt;
&lt;br /&gt;
:: If you want to do this, then you should use shortanswer questiontype.&lt;br /&gt;
&lt;br /&gt;
::&#039;&#039;&#039;In numerical questiontype the answer is a numerical value or quantity.&#039;&#039;&#039;&lt;br /&gt;
:: This is why we add tolerance grading to the numerical quantity.&lt;br /&gt;
&lt;br /&gt;
:: There is no case sensitivity in numerical question, case sensitivity in shortanswer question being the analogous to the numerical tolerance or vice versa...&lt;br /&gt;
&lt;br /&gt;
::  &#039;&#039;&#039; So when a teacher set the answer field ( and the tolerance field) in a numerical question he sets a value or a numerical quantity and PHP will understood this numercial quantity using a decimal format as 1234.56  or in exponential format as 1.23456 E3&#039;&#039;&#039; &lt;br /&gt;
::: notice that PHP in moodle always use . as decimal point.&lt;br /&gt;
::: in the edit_numerical_form or Gift import form these format with . are mandatory.&lt;br /&gt;
::: in cloze or other import the decimal point can be , in moodle 2,0.&lt;br /&gt;
&lt;br /&gt;
: in a calculated question formula answer&lt;br /&gt;
:: In calculated questiontype the numerical value or a numerical quantity will be obtained using a mathematical equation that among other element ( function, math symbol +-*/ etc.) will contain numerical quantities expressed as number.&lt;br /&gt;
::The number in the equation is written in strict PHP rule decimal format as 1234.56  or in exponential format as 1.23456 E3.&lt;br /&gt;
&lt;br /&gt;
=== The student typing its response in numerical or calculated question===&lt;br /&gt;
: in 1,9 the only decimal point allowed was .  &lt;br /&gt;
: in 2,0 the decimal point could be . or ,&lt;br /&gt;
: in 1,9 and 2,0 the thousands separator space or , (when decsep is .) where removed as need by PHP syntax.&lt;br /&gt;
&lt;br /&gt;
; THE EASIEST RULE FOR TEACHERS OR STUDENTS IS: ALWAYS USE PHP DECIMAL FORMAT  as 1234.56  or as 1.23456 E3;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; This also means that in the actual code when a teacher set the answer field , he DOES NOT set the response format&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Grading the response format : truth table==&lt;br /&gt;
&lt;br /&gt;
In the actual code 2,0 if the the decimal point and thousands sep are not set correctly by the student, he could have a zero grade to a correct numerical response.&lt;br /&gt;
&lt;br /&gt;
However a clever student will never use thousand separators and will learn once for all if he can use , or . as unit separator.&lt;br /&gt;
&lt;br /&gt;
The actual 2,1 proposal is to grade the numerical format separately from the numerical quantity.&lt;br /&gt;
&lt;br /&gt;
On analysis it appears that the best way to do this as there is already a unit penalty applied , is to add at least the decimal point as an additional answer parameter alongside the tolerance.&lt;br /&gt;
&lt;br /&gt;
A complete grading should also allow the teacher to specify the thousand separator as mandatory or control the use of the exponential format.&lt;br /&gt;
&lt;br /&gt;
given the time delays for 2,1, let&#039;s design a decimal decimal point option.&lt;br /&gt;
&lt;br /&gt;
The following table describe the results of the various versions&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle Version&lt;br /&gt;
! decsep&lt;br /&gt;
! thousand sep&lt;br /&gt;
! 1 234.56&lt;br /&gt;
! 1,234.56&lt;br /&gt;
! 1234.56&lt;br /&gt;
! 1.23456E3&lt;br /&gt;
! 1 234,56&lt;br /&gt;
! 1.234,56&lt;br /&gt;
! 1234,56&lt;br /&gt;
! 1,23456E3&lt;br /&gt;
|-&lt;br /&gt;
| 1,9&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
|-&lt;br /&gt;
| 2,0&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| NO&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
|-&lt;br /&gt;
| 2,1&lt;br /&gt;
| &#039;&#039;&#039;.&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039; ,&#039;&#039;&#039;&lt;br /&gt;
| NO&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
|-&lt;br /&gt;
| 2,1&lt;br /&gt;
| &#039;&#039;&#039;.&#039;&#039;&#039;&lt;br /&gt;
| space&lt;br /&gt;
| OK&lt;br /&gt;
| NO&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
|-&lt;br /&gt;
| 2,1&lt;br /&gt;
|&#039;&#039;&#039; ,&#039;&#039;&#039;&lt;br /&gt;
| space&lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
| OK&lt;br /&gt;
| NO&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
|-&lt;br /&gt;
| 2,1&lt;br /&gt;
|&#039;&#039;&#039; ,&#039;&#039;&#039;&lt;br /&gt;
|  .&lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
|-&lt;br /&gt;
| 2,1 proposal&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
|-&lt;br /&gt;
| 2,1 proposal&lt;br /&gt;
|  &#039;&#039;&#039;.&#039;&#039;&#039; &lt;br /&gt;
| &lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
|-&lt;br /&gt;
| 2,1proposal&lt;br /&gt;
|&#039;&#039;&#039; ,&#039;&#039;&#039;&lt;br /&gt;
| &lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
| NO&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
OR &lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle Version&lt;br /&gt;
! decsep&lt;br /&gt;
! thousand sep&lt;br /&gt;
! 1 234.56&lt;br /&gt;
! 1,234.56&lt;br /&gt;
! 1234.56&lt;br /&gt;
! 1.23456E3&lt;br /&gt;
! 1 234,56&lt;br /&gt;
! 1.234,56&lt;br /&gt;
! 1234,56&lt;br /&gt;
! 1,23456E3&lt;br /&gt;
|-&lt;br /&gt;
| 1,9&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 2,0&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| &lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
|-&lt;br /&gt;
| 2,1&lt;br /&gt;
| &#039;&#039;&#039;.&#039;&#039;&#039;&lt;br /&gt;
|&#039;&#039;&#039; ,&#039;&#039;&#039;&lt;br /&gt;
| &lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 2,1&lt;br /&gt;
| &#039;&#039;&#039;.&#039;&#039;&#039;&lt;br /&gt;
| space&lt;br /&gt;
| OK&lt;br /&gt;
| &lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 2,1&lt;br /&gt;
|&#039;&#039;&#039; ,&#039;&#039;&#039;&lt;br /&gt;
| space&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| OK&lt;br /&gt;
| &lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
|-&lt;br /&gt;
| 2,1&lt;br /&gt;
|&#039;&#039;&#039; ,&#039;&#039;&#039;&lt;br /&gt;
|  .&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
|-&lt;br /&gt;
| 2,1 proposal&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
|-&lt;br /&gt;
| 2,1 proposal&lt;br /&gt;
|  &#039;&#039;&#039;.&#039;&#039;&#039; &lt;br /&gt;
| &lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 2,1proposal&lt;br /&gt;
|&#039;&#039;&#039; ,&#039;&#039;&#039;&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
| OK&lt;br /&gt;
|}&lt;br /&gt;
In 2,1 there is no &#039;universal option&#039; that allow most of the known options and in 2,0 the german language 1.234,56 is not recognized.&lt;br /&gt;
&lt;br /&gt;
In 1,9 and 2,0 the PHP structure is always good&lt;br /&gt;
In 2,1 the PHP structure is good if you use the good thousands sep&lt;br /&gt;
&lt;br /&gt;
So there is no real  control on the thousand sep as long as the students learn to not using it.&lt;br /&gt;
&lt;br /&gt;
As a first step in grading the response format  in 2,1 , I propose that we limit the case to grade the decsep allowing either , or . and using a modified 2,0 version to handle the german . ,&lt;br /&gt;
&lt;br /&gt;
From the the table we can see, with the proposal, that upgrading or importing from 1,9 the default decsep should be set to .&lt;br /&gt;
and upgrading upgrading or importing from 2,0 the default decsep should be set to  nil i.e. universal.&lt;br /&gt;
&lt;br /&gt;
We could as set in 2,0 help warning the students that is they use , or . as thousand separators they MUST put the decimal separator.&lt;br /&gt;
&lt;br /&gt;
In 2,2 we could develop grading of thousand sep along  with the control of the exponential form.&lt;br /&gt;
&lt;br /&gt;
In all cases we need an &amp;quot;universal&amp;quot; solution for Cloze questiontype.&lt;br /&gt;
In calculated question the interface is already quite complex and perhaps things will not be implemented for 2,1 .&lt;br /&gt;
&lt;br /&gt;
==How to grade a numerical response format==&lt;br /&gt;
===Feasability of adding number format as an additional numerical answer table ===&lt;br /&gt;
&lt;br /&gt;
The answer field being set as TEXT can easily store a numerical value in any format that can be validated easily in  edit_numerical_form.php and the &lt;br /&gt;
 &amp;lt;code php&amp;gt;&lt;br /&gt;
    /**&lt;br /&gt;
     * Get an answer that contains the feedback and fraction that should be&lt;br /&gt;
     * awarded for this resonse.&lt;br /&gt;
     * @param number $value the numerical value of a response.&lt;br /&gt;
     * @return question_answer the matching answer.&lt;br /&gt;
     */&lt;br /&gt;
    public function get_matching_answer($value) {&lt;br /&gt;
        foreach ($this-&amp;gt;answers as $aid =&amp;gt; $answer) {&lt;br /&gt;
            if ($answer-&amp;gt;within_tolerance($value)) {&lt;br /&gt;
                $answer-&amp;gt;id = $aid;&lt;br /&gt;
                return $answer;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
 &amp;lt;/code&amp;gt;&lt;br /&gt;
modified accordingly.&lt;br /&gt;
&lt;br /&gt;
This is similar to tolerance handling which is another answer parameter .&lt;br /&gt;
&lt;br /&gt;
The code flow should allow to compare each answers to the different values that result from the response text.&lt;br /&gt;
&lt;br /&gt;
Aswers need to be compared with the value converted using the apply_unit() which could be different form the decsep value used, then either the $value is an array of all the values from the different decseps or the numerical value is computed inside this function from the student text response.&lt;br /&gt;
This later option could be the most flexible if we add different number formats as fractional.&lt;br /&gt;
===Keeping a separate input for the numerical response===&lt;br /&gt;
&lt;br /&gt;
# Questions should be explicit for the student.A separate input field for numerical and unit is the most evident way to do this and it is not teacher dependent although, later,  this could be set as an option.&lt;br /&gt;
# Splitting in two fields &lt;br /&gt;
## simplify the coding &lt;br /&gt;
## allow more control on the number format i.e. mandatory exponent format&lt;br /&gt;
## development of other numericals fields&lt;br /&gt;
&lt;br /&gt;
===Adding number format specification to the numerical answer===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A first version is under development with the following design &lt;br /&gt;
# add a &#039;&#039;&#039;locale&#039;&#039;&#039; parameter to the numerical_answer &lt;br /&gt;
# define three initial moodle internal locales &lt;br /&gt;
## &amp;quot;decimal_point_._,&amp;quot;, &lt;br /&gt;
## &amp;quot;decimal_point_.&amp;quot;,&lt;br /&gt;
## &amp;quot;decimal_point_,&amp;quot; &lt;br /&gt;
&lt;br /&gt;
This &#039;&#039;&#039;locale&#039;&#039;&#039; parameter could also be used later to store the official locale names.&lt;br /&gt;
&lt;br /&gt;
It allows the teacher to set different grade to different format&lt;br /&gt;
&lt;br /&gt;
[[File:grading_numerical_format.jpg]]&lt;br /&gt;
Two answers were defined &lt;br /&gt;
* one with &#039;&#039;&#039;locale&#039;&#039;&#039; &amp;quot;decimal_point_,&amp;quot; and fraction = 1 &lt;br /&gt;
* one with &#039;&#039;&#039;locale&#039;&#039;&#039; &amp;quot;decimal_point_.&amp;quot; and fraction = 0.8&lt;br /&gt;
&lt;br /&gt;
P.S. The correct format response display function code is not updated&lt;br /&gt;
&lt;br /&gt;
==How to grade the numerical response ==&lt;br /&gt;
There are 3 elements that should be graded in a numerical question&lt;br /&gt;
&lt;br /&gt;
# the numerical value&lt;br /&gt;
# the unit used in relation to the numeric value&lt;br /&gt;
# the number format used to express the value&lt;br /&gt;
&lt;br /&gt;
===the numerical value===&lt;br /&gt;
&lt;br /&gt;
We need to compare using the tolerance value the numerical answer with the numerical response obtained from &#039;&#039;&#039;locale&#039;&#039;&#039; translated response as typed by the student.&lt;br /&gt;
 This translation process associated by the various &#039;&#039;&#039;locales&#039;&#039;&#039; set &lt;br /&gt;
 by the teacher offer a possible grading of the third grading element&lt;br /&gt;
 i.e. number format.&lt;br /&gt;
&lt;br /&gt;
If there are &#039;&#039;&#039;no unit set with a multiply factor different from 1&#039;&#039;&#039; , the numerical values to test are the different answers.&lt;br /&gt;
&lt;br /&gt;
===grading the combination numerical value : unit ===&lt;br /&gt;
&lt;br /&gt;
However if there are units with factor different from unity, these unit factors generate other numerical values for each answer that when assoicate with the rigth unit, will be identical to of the answers.&lt;br /&gt;
&lt;br /&gt;
i.e.&lt;br /&gt;
answer 15 cm ( unit factor 1 ) &lt;br /&gt;
if expressed as m the good response is 0.15 m&lt;br /&gt;
&lt;br /&gt;
So the possible good numerical responses are 15 or 0.15 &lt;br /&gt;
&lt;br /&gt;
If the student response is 15 or .15 its numerical grade is 100%&lt;br /&gt;
&lt;br /&gt;
He will have a unit penalty if &lt;br /&gt;
# he gave an unrecognized unit although this should not happen as the defined units should be clearly identify in the question text&lt;br /&gt;
# if he does associate the number with the rigth unit&lt;br /&gt;
&lt;br /&gt;
The actual code does not handle differently the 2 cases.&lt;br /&gt;
&lt;br /&gt;
The question::get_matching_answer() and the question:get_matching_answer should be modified to handle &lt;br /&gt;
the unit penalty as it is handle in 2,0.&lt;br /&gt;
&lt;br /&gt;
As these functions should be in question.php the question-&amp;gt;units should be set on initialise_question_instance&lt;br /&gt;
&lt;br /&gt;
So for each answer we need to test for each non unity factor unit.&lt;br /&gt;
&lt;br /&gt;
... [[User:Pierre Pichet|Pierre Pichet]] 01:01, 18 May 2011 (WST)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Setting the answer when creating the question==&lt;br /&gt;
===A proposal===&lt;br /&gt;
The teacher should be able to set&lt;br /&gt;
# the numerical value using the PHP convention&lt;br /&gt;
# the response format , various interface can be used &lt;br /&gt;
# the tolerance&lt;br /&gt;
# the feedback&lt;br /&gt;
&lt;br /&gt;
Here a simplified proposal&lt;br /&gt;
&lt;br /&gt;
[[File:numerical_answer_interface_proposal.jpg]]&lt;br /&gt;
&lt;br /&gt;
===1,9 and 2,0 interface ===&lt;br /&gt;
In Moodle 1,9 and 2,0 in the edit_numerical_form.php, the number enter by the teacher (although student could be allowed to create question, I will use teacher for text clarity) must be conform to the PHP syntax (no thousand separator or space and . as decimal separator. E syntax is allowed.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;code php&amp;gt;                if (!(is_numeric($trimmedanswer) || $trimmedanswer == &#039;*&#039;)) {&lt;br /&gt;
                    $errors[&#039;answer[&#039; . $key . &#039;]&#039;] =&lt;br /&gt;
                            get_string(&#039;answermustbenumberorstar&#039;, &#039;qtype_numerical&#039;);&lt;br /&gt;
                }&lt;br /&gt;
 &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So the teacher must know the PHP specific number syntax.&lt;br /&gt;
&lt;br /&gt;
In the  numerical/questiontype.php    function save_question_options($question) &lt;br /&gt;
there is an additional verification mostly for numerical questions imported through various formats or inside a Cloze numerical multianswer question.&lt;br /&gt;
    &amp;lt;code php&amp;gt;         &lt;br /&gt;
                $answer-&amp;gt;answer = $this-&amp;gt;apply_unit($answerdata, $units);&lt;br /&gt;
                if ($answer-&amp;gt;answer === false) {&lt;br /&gt;
                    $result-&amp;gt;notice = get_string(&#039;invalidnumericanswer&#039;, &#039;quiz&#039;);&lt;br /&gt;
                }&lt;br /&gt;
    &amp;lt;/code&amp;gt;&lt;br /&gt;
the Moodle 2,0 apply_unit&lt;br /&gt;
   &amp;lt;code php&amp;gt; &lt;br /&gt;
    /**&lt;br /&gt;
     * Checks if the $rawresponse has a unit and applys it if appropriate.&lt;br /&gt;
     *&lt;br /&gt;
     * @param string $rawresponse  The response string to be converted to a float.&lt;br /&gt;
     * @param array $units         An array with the defined units, where the&lt;br /&gt;
     *                             unit is the key and the multiplier the value.&lt;br /&gt;
     * @return float               The rawresponse with the unit taken into&lt;br /&gt;
     *                             account as a float.&lt;br /&gt;
     */&lt;br /&gt;
    function apply_unit($rawresponse, $units) {&lt;br /&gt;
&lt;br /&gt;
        // Make units more useful&lt;br /&gt;
        $tmpunits = array();&lt;br /&gt;
        foreach ($units as $unit) {&lt;br /&gt;
            $tmpunits[$unit-&amp;gt;unit] = $unit-&amp;gt;multiplier;&lt;br /&gt;
        }&lt;br /&gt;
        // remove spaces and normalise decimal places.&lt;br /&gt;
        $rawresponse = trim($rawresponse) ;&lt;br /&gt;
        $search  = array(&#039; &#039;, &#039;,&#039;);&lt;br /&gt;
        // test if a . is present or there are multiple , (i.e. 2,456,789 ) so that we don&#039;t need spaces and ,&lt;br /&gt;
        if ( strpos($rawresponse,&#039;.&#039; ) !== false || substr_count($rawresponse,&#039;,&#039;) &amp;gt; 1 ) {&lt;br /&gt;
            $replace = array(&#039;&#039;, &#039;&#039;);&lt;br /&gt;
        }else { // remove spaces and normalise , to a . .&lt;br /&gt;
            $replace = array(&#039;&#039;, &#039;.&#039;);&lt;br /&gt;
        }&lt;br /&gt;
        $rawresponse = str_replace($search, $replace, $rawresponse);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        // Apply any unit that is present.&lt;br /&gt;
        if (ereg(&#039;^([+-]?([0-9]+(\\.[0-9]*)?|\\.[0-9]+)([eE][-+]?[0-9]+)?)([^0-9].*)?$&#039;,&lt;br /&gt;
                $rawresponse, $responseparts)) {&lt;br /&gt;
                echo&amp;quot;&amp;lt;p&amp;gt; responseparts &amp;lt;pre&amp;gt;&amp;quot;;print_r($responseparts) ;echo&amp;quot;&amp;lt;/pre&amp;gt;&amp;lt;/p&amp;gt;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
            if (!empty($responseparts[5])) {&lt;br /&gt;
&lt;br /&gt;
                if (isset($tmpunits[$responseparts[5]])) {&lt;br /&gt;
                    // Valid number with unit.&lt;br /&gt;
                    return (float)$responseparts[1] / $tmpunits[$responseparts[5]];&lt;br /&gt;
                } else {&lt;br /&gt;
                    // Valid number with invalid unit. Must be wrong.&lt;br /&gt;
                    return false;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
            } else {&lt;br /&gt;
                // Valid number without unit.&lt;br /&gt;
                return (float)$responseparts[1];&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        // Invalid number. Must be wrong.&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
 &amp;lt;/code&amp;gt;&lt;br /&gt;
The 2,0 apply_unit allows more number formats than the test in the editing form. &lt;br /&gt;
&lt;br /&gt;
* regular numbers  13500.67 : 13 500.67 : 13500,67: 13 500,67&lt;br /&gt;
&lt;br /&gt;
* if you use , as thousand separator *always* put the decimal . as in 13,500.67 : 13,500.&lt;br /&gt;
 &lt;br /&gt;
* for exponent form, say 1.350067 * 10&amp;lt;sup&amp;gt;4&amp;lt;/sup&amp;gt;, use 1.350067 E4 : 1.350067 E04 &#039;;&lt;br /&gt;
&lt;br /&gt;
The 1,9 apply_unit is more restrictive as it does not support , as decimal separator.&lt;br /&gt;
&lt;br /&gt;
More formats were allowed in 2,0 as the main objective in a numerical question is the numerical value.&lt;br /&gt;
More about this further in the page (todo)&lt;br /&gt;
&lt;br /&gt;
==Converting number in a string to a double or float variable==&lt;br /&gt;
&lt;br /&gt;
The answer is being stored in a TEXT database field or in a string in import-export files.&lt;br /&gt;
&lt;br /&gt;
However in numerical questiontype code it is used a numeric PHP parameter (float or double).&lt;br /&gt;
From http://ca2.php.net/manual/en/language.types.string.php#language.types.string.conversion&lt;br /&gt;
&lt;br /&gt;
===String conversion to numbers===&lt;br /&gt;
&lt;br /&gt;
When a string is evaluated in a numeric context, the resulting value and type are determined as follows.&lt;br /&gt;
&lt;br /&gt;
If the string *does not contain* any of the characters &#039;.&#039;, &#039;e&#039;, or &#039;E&#039; and the numeric value fits into integer type limits (as defined by PHP_INT_MAX), the string will be evaluated as an integer. In all other cases it will be evaluated as a float.&lt;br /&gt;
&lt;br /&gt;
The value is given by the initial portion of the string. If the string starts with valid numeric data, this will be the value used. Otherwise, the value will be 0 (zero). Valid numeric data is an optional sign, followed by one or more digits (optionally containing a decimal point), followed by an optional exponent. The exponent is an &#039;e&#039; or &#039;E&#039; followed by one or more digits.&lt;br /&gt;
&lt;br /&gt;
For more information on this conversion, see the Unix manual page for strtod(3).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Unix manual page for strtod====&lt;br /&gt;
http://compute.cnr.berkeley.edu/cgi-bin/man-cgi?strtod+3 &lt;br /&gt;
DESCRIPTION&lt;br /&gt;
&lt;br /&gt;
     The strtod(), strtof(), and strtold() functions convert  the&lt;br /&gt;
     initial  portion of the string pointed to by nptr to double,&lt;br /&gt;
     float, and long double representation,  respectively.  First&lt;br /&gt;
     they decompose the input string into three parts:&lt;br /&gt;
     1.  An initial,  possibly  empty,  sequence  of  white-space&lt;br /&gt;
         characters (as specified by isspace(3C))&lt;br /&gt;
     2.  A subject sequence interpreted as a floating-point  con-&lt;br /&gt;
         stant or representing infinity or NaN&lt;br /&gt;
     3.  A final string of one or more  unrecognized  characters,&lt;br /&gt;
         including the terminating null byte of the input string.&lt;br /&gt;
     Then they attempt to  convert  the  subject  sequence  to  a&lt;br /&gt;
     floating-point number, and return the result.&lt;br /&gt;
     The expected form of the subject  sequence  is  an  optional&lt;br /&gt;
     plus or minus sign, then one of the following:&lt;br /&gt;
       o  A non-empty sequence of digits optionally containing  &#039;&#039;&#039;a&lt;br /&gt;
          radix character&#039;&#039;&#039;, then an optional exponent part&lt;br /&gt;
       o  A 0x or 0X, then a non-empty  sequence  of  hexadecimal&lt;br /&gt;
          digits optionally containing a radix character, then an&lt;br /&gt;
          optional binary exponent part&lt;br /&gt;
       o  One of INF or INFINITY, ignoring case&lt;br /&gt;
...&lt;br /&gt;
     The &#039;&#039;&#039;radix character&#039;&#039;&#039;  is  defined  in  the  program&#039;s  locale&lt;br /&gt;
     (category  LC_NUMERIC).  In the POSIX locale, or in a locale&lt;br /&gt;
     where the &#039;&#039;&#039;radix character&#039;&#039;&#039; is not defined, the &#039;&#039;&#039;radix  charac-&lt;br /&gt;
     ter&#039;&#039;&#039; defaults to a period (&#039;.&#039;).&lt;br /&gt;
So if the locale LC_NUMERIC i.e.&lt;br /&gt;
&amp;lt;code php &amp;gt;&lt;br /&gt;
Array&lt;br /&gt;
(&lt;br /&gt;
    [decimal_point] =&amp;gt; .&lt;br /&gt;
    [thousands_sep] =&amp;gt; &lt;br /&gt;
    [int_curr_symbol] =&amp;gt; &lt;br /&gt;
    [currency_symbol] =&amp;gt; &lt;br /&gt;
    [mon_decimal_point] =&amp;gt; &lt;br /&gt;
    [mon_thousands_sep] =&amp;gt; &lt;br /&gt;
    [positive_sign] =&amp;gt; &lt;br /&gt;
    [negative_sign] =&amp;gt; &lt;br /&gt;
    [int_frac_digits] =&amp;gt; 127&lt;br /&gt;
    [frac_digits] =&amp;gt; 127&lt;br /&gt;
    [p_cs_precedes] =&amp;gt; 127&lt;br /&gt;
    [p_sep_by_space] =&amp;gt; 127&lt;br /&gt;
    [n_cs_precedes] =&amp;gt; 127&lt;br /&gt;
    [n_sep_by_space] =&amp;gt; 127&lt;br /&gt;
    [p_sign_posn] =&amp;gt; 127&lt;br /&gt;
    [n_sign_posn] =&amp;gt; 127&lt;br /&gt;
    [grouping] =&amp;gt; Array&lt;br /&gt;
        (&lt;br /&gt;
        )&lt;br /&gt;
&lt;br /&gt;
    [mon_grouping] =&amp;gt; Array&lt;br /&gt;
        (&lt;br /&gt;
        )&lt;br /&gt;
&lt;br /&gt;
 )&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
define &#039;&#039;&#039;decimal_point&#039;&#039;&#039; not as . as here but as , then 1,234.56 will be recognized as 1,234 i.e. smaller than 2 although the number written is greater than 1000. &lt;br /&gt;
==== PHP 5.36 zend_strtod()====&lt;br /&gt;
However in PHP 5.3.6 strtod() is replaced by zend_strtod()&lt;br /&gt;
&amp;lt;code c &amp;gt;&lt;br /&gt;
 ZEND_API double zend_strtod (CONST char *s00, char **se)&lt;br /&gt;
 {&lt;br /&gt;
	int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign,&lt;br /&gt;
		e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign;&lt;br /&gt;
	CONST char *s, *s0, *s1;&lt;br /&gt;
	volatile double aadj, aadj1, adj;&lt;br /&gt;
	volatile _double rv, rv0;&lt;br /&gt;
	Long L;&lt;br /&gt;
	ULong y, z;&lt;br /&gt;
	Bigint *bb, *bb1, *bd, *bd0, *bs, *delta, *tmp;&lt;br /&gt;
	double result;&lt;br /&gt;
&lt;br /&gt;
	&#039;&#039;&#039;CONST char decimal_point = &#039;.&#039;;&#039;&#039;&#039;&lt;br /&gt;
   ...&lt;br /&gt;
			z = 10*z + c - &#039;0&#039;;&lt;br /&gt;
	nd0 = nd;&lt;br /&gt;
	if (c == decimal_point) {&lt;br /&gt;
		c = *++s;&lt;br /&gt;
		if (!nd) {&lt;br /&gt;
			for(; c == &#039;0&#039;; c = *++s)&lt;br /&gt;
				nz++;&lt;br /&gt;
			if (c &amp;gt; &#039;0&#039; &amp;amp;&amp;amp; c &amp;lt;= &#039;9&#039;) {&lt;br /&gt;
				s0 = s;&lt;br /&gt;
				nf += nz;&lt;br /&gt;
				nz = 0;&lt;br /&gt;
				goto have_dig;&lt;br /&gt;
			}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt; &lt;br /&gt;
 &lt;br /&gt;
&#039;&#039;&#039;So in PHP 5.3.6 the zend_strtod() ALWAYS use . as decimal_point&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Other functions allow the user to define the decimal_point or use the locale defined decimal_point.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
=== is_numeric()===&lt;br /&gt;
&amp;lt;code c&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Checks whether the string &amp;quot;str&amp;quot; with length &amp;quot;length&amp;quot; is numeric. The value&lt;br /&gt;
 * of allow_errors determines whether it&#039;s required to be entirely numeric, or&lt;br /&gt;
 * just its prefix. Leading whitespace is allowed.&lt;br /&gt;
 *&lt;br /&gt;
 * The function returns 0 if the string did not contain a valid number; IS_LONG&lt;br /&gt;
 * if it contained a number that fits within the range of a long; or IS_DOUBLE&lt;br /&gt;
 * if the number was out of long range or contained a decimal point/exponent.&lt;br /&gt;
 * The number&#039;s value is returned into the respective pointer, *lval or *dval,&lt;br /&gt;
 * if that pointer is not NULL.&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
static inline zend_uchar is_numeric_string(const char *str, int length, long *lval, double *dval, int allow_errors)&lt;br /&gt;
{&lt;br /&gt;
	const char *ptr;&lt;br /&gt;
	int base = 10, digits = 0, dp_or_e = 0;&lt;br /&gt;
	double local_dval;&lt;br /&gt;
	zend_uchar type;&lt;br /&gt;
&lt;br /&gt;
	if (!length) {&lt;br /&gt;
		return 0;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	/* Skip any whitespace&lt;br /&gt;
	 * This is much faster than the isspace() function */&lt;br /&gt;
	while (*str == &#039; &#039; || *str == &#039;\t&#039; || *str == &#039;\n&#039; || *str == &#039;\r&#039; || *str == &#039;\v&#039; || *str == &#039;\f&#039;) {&lt;br /&gt;
		str++;&lt;br /&gt;
		length--;&lt;br /&gt;
	}&lt;br /&gt;
	ptr = str;&lt;br /&gt;
&lt;br /&gt;
	if (*ptr == &#039;-&#039; || *ptr == &#039;+&#039;) {&lt;br /&gt;
		ptr++;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	if (ZEND_IS_DIGIT(*ptr)) {&lt;br /&gt;
		/* Handle hex numbers&lt;br /&gt;
		 * str is used instead of ptr to disallow signs and keep old behavior */&lt;br /&gt;
		if (length &amp;gt; 2 &amp;amp;&amp;amp; *str == &#039;0&#039; &amp;amp;&amp;amp; (str[1] == &#039;x&#039; || str[1] == &#039;X&#039;)) {&lt;br /&gt;
			base = 16;&lt;br /&gt;
			ptr += 2;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		/* Skip any leading 0s */&lt;br /&gt;
		while (*ptr == &#039;0&#039;) {&lt;br /&gt;
			ptr++;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		/* Count the number of digits. If a decimal point/exponent is found,&lt;br /&gt;
		 * it&#039;s a double. Otherwise, if there&#039;s a dval or no need to check for&lt;br /&gt;
		 * a full match, stop when there are too many digits for a long */&lt;br /&gt;
		for (type = IS_LONG; !(digits &amp;gt;= MAX_LENGTH_OF_LONG &amp;amp;&amp;amp; (dval || allow_errors == 1)); digits++, ptr++) {&lt;br /&gt;
check_digits:&lt;br /&gt;
			if (ZEND_IS_DIGIT(*ptr) || (base == 16 &amp;amp;&amp;amp; ZEND_IS_XDIGIT(*ptr))) {&lt;br /&gt;
				continue;&lt;br /&gt;
			} else if (base == 10) {&lt;br /&gt;
				if (*ptr == &#039;.&#039; &amp;amp;&amp;amp; dp_or_e &amp;lt; 1) {&lt;br /&gt;
					goto process_double;&lt;br /&gt;
				} else if ((*ptr == &#039;e&#039; || *ptr == &#039;E&#039;) &amp;amp;&amp;amp; dp_or_e &amp;lt; 2) {&lt;br /&gt;
					const char *e = ptr + 1;&lt;br /&gt;
&lt;br /&gt;
					if (*e == &#039;-&#039; || *e == &#039;+&#039;) {&lt;br /&gt;
						ptr = e++;&lt;br /&gt;
					}&lt;br /&gt;
					if (ZEND_IS_DIGIT(*e)) {&lt;br /&gt;
						goto process_double;&lt;br /&gt;
					}&lt;br /&gt;
				}&lt;br /&gt;
			}&lt;br /&gt;
&lt;br /&gt;
			break;&lt;br /&gt;
		}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The decimal point is hard written in the code &#039;&#039;&#039;if (*ptr == &#039;.&#039; &amp;amp;&amp;amp; dp_or_e &amp;lt; 1)&#039;&#039;&#039;, so the test will not be locale dependent.&lt;br /&gt;
&lt;br /&gt;
Note that this function allows hexadecimal written numbers so in numerical we need another function (like apply_unit() to only use decimals.&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34931</id>
		<title>Question Engine 2:Numerical tolerances</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34931"/>
		<updated>2012-08-17T14:02:27Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: /* Tests results */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Analysis of the various tolerances for numerical and calculated question type answer see (MDL-31837)&lt;br /&gt;
&lt;br /&gt;
In grading a numerical response, the (student) numerical value is compared to the answer numerical value.&lt;br /&gt;
&lt;br /&gt;
This comparison allow a tolerance that is associated with the answer and that can be expressed in various ways.&lt;br /&gt;
&lt;br /&gt;
For calculated question answers the tolerance can be of 3 different types: relative, nominal or geometric. &lt;br /&gt;
=Limits of real numbers in PHP=&lt;br /&gt;
&lt;br /&gt;
The following is from http://www.php.net/manual/en/language.types.float.php&lt;br /&gt;
&lt;br /&gt;
The size of a float is platform-dependent, although a maximum of ~1.8e308 with a precision of roughly 14 decimal digits is a common value (the 64 bit IEEE format).&lt;br /&gt;
&lt;br /&gt;
 Warning&lt;br /&gt;
 Floating point precision&lt;br /&gt;
&lt;br /&gt;
Floating point numbers have limited precision. Although it depends on the system, PHP typically uses the IEEE 754 double precision format, which will give a maximum relative error due to rounding in the order of 1.11e-16. Non elementary arithmetic operations may give larger errors, and, of course, error propagation must be considered when several operations are compounded.&lt;br /&gt;
&lt;br /&gt;
Additionally, rational numbers that are exactly representable as floating point numbers in base 10, like 0.1 or 0.7, do not have an exact representation as floating point numbers in base 2, which is used internally, no matter the size of the mantissa. Hence, they cannot be converted into their internal binary counterparts without a small loss of precision. This can lead to confusing results: for example, floor((0.1+0.7)*10) will usually return 7 instead of the expected 8, since the internal representation will be something like 7.9999999999999991118....&lt;br /&gt;
&lt;br /&gt;
So never trust floating number results to the last digit, and do not compare floating point numbers directly for equality. If higher precision is necessary, the arbitrary precision math functions and gmp functions are available.&lt;br /&gt;
&lt;br /&gt;
Since the internal representation is in base 2, 0 and 1 will have the same exponent so the precision ( i.e. init_get(&#039;precision&#039;) should have the same value.?&lt;br /&gt;
&lt;br /&gt;
....&lt;br /&gt;
=1,9 version=&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
function get_tolerance_interval(&amp;amp;$answer) {&lt;br /&gt;
        // No tolerance&lt;br /&gt;
        if (empty($answer-&amp;gt;tolerance)) {&lt;br /&gt;
            $answer-&amp;gt;tolerance = 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Calculate the interval of correct responses (min/max)&lt;br /&gt;
        if (!isset($answer-&amp;gt;tolerancetype)) {&lt;br /&gt;
            $answer-&amp;gt;tolerancetype = 2; // nominal&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make the&lt;br /&gt;
        // comparison work correctly. Otherwise seemingly equal values can yield&lt;br /&gt;
        // false. (fixes bug #3225)&lt;br /&gt;
        $tolerance = (float)$answer-&amp;gt;tolerance + (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;));&lt;br /&gt;
        switch ($answer-&amp;gt;tolerancetype) {&lt;br /&gt;
            case &#039;1&#039;: case &#039;relative&#039;:&lt;br /&gt;
                /// Recalculate the tolerance and fall through&lt;br /&gt;
                /// to the nominal case:&lt;br /&gt;
                $tolerance = $answer-&amp;gt;answer * $tolerance;&lt;br /&gt;
                // Do not fall through to the nominal case because the tiny fraction is a factor of the answer&lt;br /&gt;
                 $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;2&#039;: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                // $answer-&amp;gt;tolerance 0 or something else&lt;br /&gt;
                if ((float)$answer-&amp;gt;tolerance == 0.0  &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance ){&lt;br /&gt;
                    $tolerance = (float) (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) * abs((float)$answer-&amp;gt;answer) ; //tiny fraction&lt;br /&gt;
                } else if ((float)$answer-&amp;gt;tolerance != 0.0 &amp;amp;&amp;amp; abs((float)$answer-&amp;gt;tolerance) &amp;lt; abs((float)$answer-&amp;gt;answer) &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance){&lt;br /&gt;
                    $tolerance = (1+(&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) )* abs((float) $answer-&amp;gt;tolerance) ;//tiny fraction&lt;br /&gt;
               }&lt;br /&gt;
&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;3&#039;: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                $max = $answer-&amp;gt;answer * $quotient;&lt;br /&gt;
                $min = $answer-&amp;gt;answer / $quotient;&lt;br /&gt;
                break;&lt;br /&gt;
            default:&lt;br /&gt;
                error(&amp;quot;Unknown tolerance type $answer-&amp;gt;tolerancetype&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $answer-&amp;gt;min = $min;&lt;br /&gt;
        $answer-&amp;gt;max = $max;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 actual code=&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class qtype_numerical_answer extends question_answer {&lt;br /&gt;
    /** @var float allowable margin of error. */&lt;br /&gt;
    public $tolerance;&lt;br /&gt;
    /** @var integer|string see {@link get_tolerance_interval()} for the meaning of this value. */&lt;br /&gt;
    public $tolerancetype = 2;&lt;br /&gt;
&lt;br /&gt;
    public function __construct($id, $answer, $fraction, $feedback, $feedbackformat, $tolerance) {&lt;br /&gt;
        parent::__construct($id, $answer, $fraction, $feedback, $feedbackformat);&lt;br /&gt;
        $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_tolerance_interval() {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            throw new coding_exception(&#039;Cannot work out tolerance interval for answer *.&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make&lt;br /&gt;
        // the comparison work correctly, otherwise seemingly equal values can&lt;br /&gt;
        // yield false. See MDL-3225.&lt;br /&gt;
        $tolerance = (float) $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;));&lt;br /&gt;
&lt;br /&gt;
        switch ($this-&amp;gt;tolerancetype) {&lt;br /&gt;
            case 1: case &#039;relative&#039;:&lt;br /&gt;
                $range = abs($this-&amp;gt;answer) * $tolerance;&lt;br /&gt;
                return array($this-&amp;gt;answer - $range, $this-&amp;gt;answer + $range);&lt;br /&gt;
&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) *&lt;br /&gt;
                        max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&lt;br /&gt;
            case 3: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                return array($this-&amp;gt;answer / $quotient, $this-&amp;gt;answer * $quotient);&lt;br /&gt;
&lt;br /&gt;
            default:&lt;br /&gt;
                throw new coding_exception(&#039;Unknown tolerance type &#039; . $this-&amp;gt;tolerancetype);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function within_tolerance($value) {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
        list($min, $max) = $this-&amp;gt;get_tolerance_interval();&lt;br /&gt;
        return $min &amp;lt;= $value &amp;amp;&amp;amp; $value &amp;lt;= $max;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 vs 1,9 differences=&lt;br /&gt;
== case relative ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case geometric ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case nominal ==&lt;br /&gt;
The use of &lt;br /&gt;
 pow(10, -1 * ini_get(&#039;precision&#039;)) * max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
The &#039;tiny fraction&#039; part of the tolerance  is not related to the answer when the answer is less than 1. &lt;br /&gt;
&lt;br /&gt;
We should get back to the 1,9 equivalent code first by removing the max function &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The 1,9 code has a special treatment of the answer == 0 .&lt;br /&gt;
&lt;br /&gt;
Should we keep the code ?&lt;br /&gt;
&lt;br /&gt;
=== Answer is 0===&lt;br /&gt;
What is the precision of 0 ?&lt;br /&gt;
It cannot be 0 , it only can be the precision of the digital part of the number i.e.  pow(10, -1 * ini_get(&#039;precision&#039;)).&lt;br /&gt;
As a mather of fact the exponent part of 0 is the same one as 1 so its precision is the same.&lt;br /&gt;
We should not forget that the &amp;quot;turning point&amp;quot; (positive to negative)  of real number exponent value is 1 not 0.&lt;br /&gt;
&lt;br /&gt;
So to get the &amp;quot;tiny number&amp;quot; we should multiply the  pow(10, -1 * ini_get(&#039;precision&#039;)) by $this-&amp;gt;answer except when $this-&amp;gt;answer == 0 when it should be 1.&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 0,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;pow(10, -1 * ini_get(&#039;precision&#039;))=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
&lt;br /&gt;
=== Answer is NOT 0===&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;tiny part&amp;quot; should mostly be calculated as pow(10, -1 * ini_get(&#039;precision&#039;))*$answer&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 2,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;=pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))** $this-&amp;gt;answer ;&lt;br /&gt;
&lt;br /&gt;
=Code flow proposal=&lt;br /&gt;
&lt;br /&gt;
This code reflects the discussion although a more concise version could be built.&lt;br /&gt;
The proposal is somehow different from the 1,9 version as it includes the precision of the tolerance in the range.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    if ($this-&amp;gt;answer == 0.0){&lt;br /&gt;
         if($this-&amp;gt;tolerance == 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)){ // the 0&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         }&lt;br /&gt;
   } else {&lt;br /&gt;
         if($this-&amp;gt;tolerance === 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer) ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)* abs($this-&amp;gt;answer)){ &lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
         }     &lt;br /&gt;
   }         &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Tim&#039;s idea==&lt;br /&gt;
&lt;br /&gt;
I am wondering whether it works just change &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the 2.0 code to&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max($this-&amp;gt;tolerance, abs($this-&amp;gt;answer), pow(10, -1 * ini_get(&#039;precision&#039;)));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code might be nicer if we define $epsilon = pow(10, -1 * ini_get(&#039;precision&#039;)) at the start of the function.&lt;br /&gt;
&lt;br /&gt;
Finally, I would like to know what tests you propose to add to question/type/numerical/tests/answer_test.php in order to demonstrate that everything is working properly. In particular, what tests would you like to add that will fail with the current code, but which will pass once we have fixed this bug?&lt;br /&gt;
&lt;br /&gt;
--[[User:Tim Hunt|Tim Hunt]] 00:53, 16 August 2012 (WST)&lt;br /&gt;
==Pierre&#039;s comment==&lt;br /&gt;
Thanks for your code expert feedback...&lt;br /&gt;
&lt;br /&gt;
I am using a simple calculated question on 2,0 or a calculated question on 1,9  to test the various combinations with different answers and tolerances.&lt;br /&gt;
&lt;br /&gt;
The range (Min- Max ) is available directly.&lt;br /&gt;
&lt;br /&gt;
At first tests your proposal seems to be working.&lt;br /&gt;
&lt;br /&gt;
I will report here the results of various tests on 1,9, actual 2, your proposal and the more linear code.&lt;br /&gt;
&lt;br /&gt;
This should help us to choose which tests to use.&lt;br /&gt;
&lt;br /&gt;
[[User:Pierre Pichet|Pierre Pichet]] 12:38, 16 August 2012 (WST)&lt;br /&gt;
&lt;br /&gt;
=Tests results=&lt;br /&gt;
==Testing Min-Max==&lt;br /&gt;
Types&lt;br /&gt;
* R :relative &lt;br /&gt;
*N  :nominal &lt;br /&gt;
*G  : geometric&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Answer!!Tolerance !!Type    !! 1,9 Min!! 1,9 Max!! Code Min !! Code Max!! 2,0 Min!! 2,0 Max!! Tim Min!! Tim Max&lt;br /&gt;
|-&lt;br /&gt;
|0          ||  0          ||  N      ||  0        ||  0    ||  -1.0E-14 ||  1.0E-14||  -1.0E-14  ||  1.0E-14  || -1.0E-28    ||  1.0E-28      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  1e-24    ||  N    || 0   || 0    ||  -1.0E-24 ||  1.0E-24||  -1.0000000001E-14   ||  +1.0000000001E-14   ||  -1.0001E-24    ||  1.0001E-24     &lt;br /&gt;
|-&lt;br /&gt;
|1e-20          ||  0   ||  N|| 9.9999999999999E-21  ||  1.0E-20    ||  9.9999999999999E-21 ||  1.0E-20||  -9.99999E-15   ||  1.000001E-14   || 9.9999999999999E-21    ||  1.0E-20     &lt;br /&gt;
|-&lt;br /&gt;
|1e-20          ||  1e-24    || N || 9.999E-21   ||  1.0001E-20|| 9.999E-21||1.0001E-20 ||  -9.999990001E-15   ||  1.0000010001E-14   ||  9.9989999E-21    ||  1.00010001E-20      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The tests on master, Tim proposal and code proposal are done on the same installation just changing the branchs (master) created for the tests so everything else is constant.&lt;br /&gt;
&lt;br /&gt;
The Code proposal give similar results to the 1,9 version with a more precise handling of 0 as answer.&lt;br /&gt;
&lt;br /&gt;
TODO : Review the Code proposal , use as suggested $epsilon, ....&lt;br /&gt;
==HOW PHP handle 0==&lt;br /&gt;
Here the results from different 0 answers using Tim&#039;s code&lt;br /&gt;
&lt;br /&gt;
 0.0 = 0&lt;br /&gt;
 Correct answer : 0 inside limits of true value 0.0&lt;br /&gt;
 Min: -1.0001E-24 --- Max: 1.0001E-24&lt;br /&gt;
 &lt;br /&gt;
 0+0.00000000000000000000001 = 1.00000000e-23&lt;br /&gt;
 Correct answer : 1.00000000e-23 inside limits of true value 0+0.00000000000000000000001&lt;br /&gt;
 Min: 9.9999E-24 --- Max: 1.00001E-23&lt;br /&gt;
&lt;br /&gt;
 1-1.000000000000000001 = 0&lt;br /&gt;
 Correct answer : 0 inside limits of true value 1-1.000000000000000001&lt;br /&gt;
 Min: -1.0E-28 --- Max: 1.0E-28&lt;br /&gt;
&lt;br /&gt;
 1-1.0000000000000001 = 0&lt;br /&gt;
 Correct answer : 0 inside limits of true value 1-1.0000000000000001&lt;br /&gt;
 Min: -1.0E-28 --- Max: 1.0E-28&lt;br /&gt;
&lt;br /&gt;
 1-1.000000000000001 = -1.11022302e-15&lt;br /&gt;
 ERROR Correct answer : -1.11022302e-15 outside limits of true value 1-1.000000000000001&lt;br /&gt;
 Min: -1.1102230246253E-15 --- Max: -1.1102230246251E-15&lt;br /&gt;
 &lt;br /&gt;
In the first one when PHP decode the answer, it detect the first 0 than detect the second term as 1e-23 which is not zero.&lt;br /&gt;
&lt;br /&gt;
When PHP add the 2 numbers, the answer is 1.00000000e-23&lt;br /&gt;
&lt;br /&gt;
In the second answer he convert &lt;br /&gt;
&lt;br /&gt;
1 to 1.000000000000  &lt;br /&gt;
&lt;br /&gt;
and&lt;br /&gt;
&lt;br /&gt;
1.0000000000000001 to 1.000000000000   i.e. to its epsilon limit&lt;br /&gt;
&lt;br /&gt;
which when substacted will give 0.0 &lt;br /&gt;
&lt;br /&gt;
This could occur only on calculated questions as there is no equation in numerical.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==TESTING GRADING==&lt;br /&gt;
In order to test how the code handle responses I create a question with 3 answers&lt;br /&gt;
* A dummy answer {x} to have at least one parameter used in an answer.&lt;br /&gt;
* Answer 0 Nominal Tolerance 0 Grade 100%&lt;br /&gt;
* Answer 0 Nominal Tolerance 1e-20&lt;br /&gt;
&lt;br /&gt;
=Final Code proposal=&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    if ($this-&amp;gt;answer == 0.0){&lt;br /&gt;
         if($this-&amp;gt;tolerance == 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)){ // the 0&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         }&lt;br /&gt;
   } else {&lt;br /&gt;
         if($this-&amp;gt;tolerance === 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer) ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)* abs($this-&amp;gt;answer)){ &lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
         }     &lt;br /&gt;
   }         &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This &amp;quot;linear&amp;quot; code can be rewritten differently : &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
     if ($this-&amp;gt;answer == 0.0){&lt;br /&gt;
         if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)){ // the 0&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         }&lt;br /&gt;
   } else {&lt;br /&gt;
         if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)* abs($this-&amp;gt;answer)){ &lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
         }&lt;br /&gt;
   } &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
If we add &lt;br /&gt;
&lt;br /&gt;
    $epsilon = pow(10, -1 * ini_get(&#039;precision&#039;));&lt;br /&gt;
&lt;br /&gt;
then&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34925</id>
		<title>Question Engine 2:Numerical tolerances</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34925"/>
		<updated>2012-08-17T05:16:50Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: /* Final Code proposal */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Analysis of the various tolerances for numerical and calculated question type answer see (MDL-31837)&lt;br /&gt;
&lt;br /&gt;
In grading a numerical response, the (student) numerical value is compared to the answer numerical value.&lt;br /&gt;
&lt;br /&gt;
This comparison allow a tolerance that is associated with the answer and that can be expressed in various ways.&lt;br /&gt;
&lt;br /&gt;
For calculated question answers the tolerance can be of 3 different types: relative, nominal or geometric. &lt;br /&gt;
=Limits of real numbers in PHP=&lt;br /&gt;
&lt;br /&gt;
The following is from http://www.php.net/manual/en/language.types.float.php&lt;br /&gt;
&lt;br /&gt;
The size of a float is platform-dependent, although a maximum of ~1.8e308 with a precision of roughly 14 decimal digits is a common value (the 64 bit IEEE format).&lt;br /&gt;
&lt;br /&gt;
 Warning&lt;br /&gt;
 Floating point precision&lt;br /&gt;
&lt;br /&gt;
Floating point numbers have limited precision. Although it depends on the system, PHP typically uses the IEEE 754 double precision format, which will give a maximum relative error due to rounding in the order of 1.11e-16. Non elementary arithmetic operations may give larger errors, and, of course, error propagation must be considered when several operations are compounded.&lt;br /&gt;
&lt;br /&gt;
Additionally, rational numbers that are exactly representable as floating point numbers in base 10, like 0.1 or 0.7, do not have an exact representation as floating point numbers in base 2, which is used internally, no matter the size of the mantissa. Hence, they cannot be converted into their internal binary counterparts without a small loss of precision. This can lead to confusing results: for example, floor((0.1+0.7)*10) will usually return 7 instead of the expected 8, since the internal representation will be something like 7.9999999999999991118....&lt;br /&gt;
&lt;br /&gt;
So never trust floating number results to the last digit, and do not compare floating point numbers directly for equality. If higher precision is necessary, the arbitrary precision math functions and gmp functions are available.&lt;br /&gt;
&lt;br /&gt;
Since the internal representation is in base 2, 0 and 1 will have the same exponent so the precision ( i.e. init_get(&#039;precision&#039;) should have the same value.?&lt;br /&gt;
&lt;br /&gt;
....&lt;br /&gt;
=1,9 version=&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
function get_tolerance_interval(&amp;amp;$answer) {&lt;br /&gt;
        // No tolerance&lt;br /&gt;
        if (empty($answer-&amp;gt;tolerance)) {&lt;br /&gt;
            $answer-&amp;gt;tolerance = 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Calculate the interval of correct responses (min/max)&lt;br /&gt;
        if (!isset($answer-&amp;gt;tolerancetype)) {&lt;br /&gt;
            $answer-&amp;gt;tolerancetype = 2; // nominal&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make the&lt;br /&gt;
        // comparison work correctly. Otherwise seemingly equal values can yield&lt;br /&gt;
        // false. (fixes bug #3225)&lt;br /&gt;
        $tolerance = (float)$answer-&amp;gt;tolerance + (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;));&lt;br /&gt;
        switch ($answer-&amp;gt;tolerancetype) {&lt;br /&gt;
            case &#039;1&#039;: case &#039;relative&#039;:&lt;br /&gt;
                /// Recalculate the tolerance and fall through&lt;br /&gt;
                /// to the nominal case:&lt;br /&gt;
                $tolerance = $answer-&amp;gt;answer * $tolerance;&lt;br /&gt;
                // Do not fall through to the nominal case because the tiny fraction is a factor of the answer&lt;br /&gt;
                 $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;2&#039;: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                // $answer-&amp;gt;tolerance 0 or something else&lt;br /&gt;
                if ((float)$answer-&amp;gt;tolerance == 0.0  &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance ){&lt;br /&gt;
                    $tolerance = (float) (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) * abs((float)$answer-&amp;gt;answer) ; //tiny fraction&lt;br /&gt;
                } else if ((float)$answer-&amp;gt;tolerance != 0.0 &amp;amp;&amp;amp; abs((float)$answer-&amp;gt;tolerance) &amp;lt; abs((float)$answer-&amp;gt;answer) &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance){&lt;br /&gt;
                    $tolerance = (1+(&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) )* abs((float) $answer-&amp;gt;tolerance) ;//tiny fraction&lt;br /&gt;
               }&lt;br /&gt;
&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;3&#039;: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                $max = $answer-&amp;gt;answer * $quotient;&lt;br /&gt;
                $min = $answer-&amp;gt;answer / $quotient;&lt;br /&gt;
                break;&lt;br /&gt;
            default:&lt;br /&gt;
                error(&amp;quot;Unknown tolerance type $answer-&amp;gt;tolerancetype&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $answer-&amp;gt;min = $min;&lt;br /&gt;
        $answer-&amp;gt;max = $max;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 actual code=&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class qtype_numerical_answer extends question_answer {&lt;br /&gt;
    /** @var float allowable margin of error. */&lt;br /&gt;
    public $tolerance;&lt;br /&gt;
    /** @var integer|string see {@link get_tolerance_interval()} for the meaning of this value. */&lt;br /&gt;
    public $tolerancetype = 2;&lt;br /&gt;
&lt;br /&gt;
    public function __construct($id, $answer, $fraction, $feedback, $feedbackformat, $tolerance) {&lt;br /&gt;
        parent::__construct($id, $answer, $fraction, $feedback, $feedbackformat);&lt;br /&gt;
        $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_tolerance_interval() {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            throw new coding_exception(&#039;Cannot work out tolerance interval for answer *.&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make&lt;br /&gt;
        // the comparison work correctly, otherwise seemingly equal values can&lt;br /&gt;
        // yield false. See MDL-3225.&lt;br /&gt;
        $tolerance = (float) $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;));&lt;br /&gt;
&lt;br /&gt;
        switch ($this-&amp;gt;tolerancetype) {&lt;br /&gt;
            case 1: case &#039;relative&#039;:&lt;br /&gt;
                $range = abs($this-&amp;gt;answer) * $tolerance;&lt;br /&gt;
                return array($this-&amp;gt;answer - $range, $this-&amp;gt;answer + $range);&lt;br /&gt;
&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) *&lt;br /&gt;
                        max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&lt;br /&gt;
            case 3: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                return array($this-&amp;gt;answer / $quotient, $this-&amp;gt;answer * $quotient);&lt;br /&gt;
&lt;br /&gt;
            default:&lt;br /&gt;
                throw new coding_exception(&#039;Unknown tolerance type &#039; . $this-&amp;gt;tolerancetype);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function within_tolerance($value) {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
        list($min, $max) = $this-&amp;gt;get_tolerance_interval();&lt;br /&gt;
        return $min &amp;lt;= $value &amp;amp;&amp;amp; $value &amp;lt;= $max;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 vs 1,9 differences=&lt;br /&gt;
== case relative ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case geometric ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case nominal ==&lt;br /&gt;
The use of &lt;br /&gt;
 pow(10, -1 * ini_get(&#039;precision&#039;)) * max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
The &#039;tiny fraction&#039; part of the tolerance  is not related to the answer when the answer is less than 1. &lt;br /&gt;
&lt;br /&gt;
We should get back to the 1,9 equivalent code first by removing the max function &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The 1,9 code has a special treatment of the answer == 0 .&lt;br /&gt;
&lt;br /&gt;
Should we keep the code ?&lt;br /&gt;
&lt;br /&gt;
=== Answer is 0===&lt;br /&gt;
What is the precision of 0 ?&lt;br /&gt;
It cannot be 0 , it only can be the precision of the digital part of the number i.e.  pow(10, -1 * ini_get(&#039;precision&#039;)).&lt;br /&gt;
As a mather of fact the exponent part of 0 is the same one as 1 so its precision is the same.&lt;br /&gt;
We should not forget that the &amp;quot;turning point&amp;quot; (positive to negative)  of real number exponent value is 1 not 0.&lt;br /&gt;
&lt;br /&gt;
So to get the &amp;quot;tiny number&amp;quot; we should multiply the  pow(10, -1 * ini_get(&#039;precision&#039;)) by $this-&amp;gt;answer except when $this-&amp;gt;answer == 0 when it should be 1.&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 0,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;pow(10, -1 * ini_get(&#039;precision&#039;))=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
&lt;br /&gt;
=== Answer is NOT 0===&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;tiny part&amp;quot; should mostly be calculated as pow(10, -1 * ini_get(&#039;precision&#039;))*$answer&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 2,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;=pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))** $this-&amp;gt;answer ;&lt;br /&gt;
&lt;br /&gt;
=Code flow proposal=&lt;br /&gt;
&lt;br /&gt;
This code reflects the discussion although a more concise version could be built.&lt;br /&gt;
The proposal is somehow different from the 1,9 version as it includes the precision of the tolerance in the range.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    if ($this-&amp;gt;answer == 0.0){&lt;br /&gt;
         if($this-&amp;gt;tolerance == 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)){ // the 0&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         }&lt;br /&gt;
   } else {&lt;br /&gt;
         if($this-&amp;gt;tolerance === 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer) ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)* abs($this-&amp;gt;answer)){ &lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
         }     &lt;br /&gt;
   }         &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Tim&#039;s idea==&lt;br /&gt;
&lt;br /&gt;
I am wondering whether it works just change &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the 2.0 code to&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max($this-&amp;gt;tolerance, abs($this-&amp;gt;answer), pow(10, -1 * ini_get(&#039;precision&#039;)));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code might be nicer if we define $epsilon = pow(10, -1 * ini_get(&#039;precision&#039;)) at the start of the function.&lt;br /&gt;
&lt;br /&gt;
Finally, I would like to know what tests you propose to add to question/type/numerical/tests/answer_test.php in order to demonstrate that everything is working properly. In particular, what tests would you like to add that will fail with the current code, but which will pass once we have fixed this bug?&lt;br /&gt;
&lt;br /&gt;
--[[User:Tim Hunt|Tim Hunt]] 00:53, 16 August 2012 (WST)&lt;br /&gt;
==Pierre&#039;s comment==&lt;br /&gt;
Thanks for your code expert feedback...&lt;br /&gt;
&lt;br /&gt;
I am using a simple calculated question on 2,0 or a calculated question on 1,9  to test the various combinations with different answers and tolerances.&lt;br /&gt;
&lt;br /&gt;
The range (Min- Max ) is available directly.&lt;br /&gt;
&lt;br /&gt;
At first tests your proposal seems to be working.&lt;br /&gt;
&lt;br /&gt;
I will report here the results of various tests on 1,9, actual 2, your proposal and the more linear code.&lt;br /&gt;
&lt;br /&gt;
This should help us to choose which tests to use.&lt;br /&gt;
&lt;br /&gt;
[[User:Pierre Pichet|Pierre Pichet]] 12:38, 16 August 2012 (WST)&lt;br /&gt;
&lt;br /&gt;
=Tests results=&lt;br /&gt;
Types&lt;br /&gt;
* R :relative &lt;br /&gt;
*N  :nominal &lt;br /&gt;
*G  : geometric&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Answer!!Tolerance !!Type    !! 1,9 Min!! 1,9 Max!! Code Min !! Code Max!! 2,0 Min!! 2,0 Max!! Tim Min!! Tim Max&lt;br /&gt;
|-&lt;br /&gt;
|0          ||  0          ||  N      ||  0        ||  0    ||  -1.0E-14 ||  1.0E-14||  -1.0E-14  ||  1.0E-14  || -1.0E-28    ||  1.0E-28      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  1e-24    ||  N    || 0   || 0    ||  -1.0E-24 ||  1.0E-24||  -1.0000000001E-14   ||  +1.0000000001E-14   ||  -1.0001E-24    ||  1.0001E-24     &lt;br /&gt;
|-&lt;br /&gt;
|1e-20          ||  0   ||  N|| 9.9999999999999E-21  ||  1.0E-20    ||  9.9999999999999E-21 ||  1.0E-20||  -9.99999E-15   ||  1.000001E-14   || 9.9999999999999E-21    ||  1.0E-20     &lt;br /&gt;
|-&lt;br /&gt;
|1e-20          ||  1e-24    || N || 9.999E-21   ||  1.0001E-20|| 9.999E-21||1.0001E-20 ||  -9.999990001E-15   ||  1.0000010001E-14   ||  9.9989999E-21    ||  1.00010001E-20      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The tests on master, Tim proposal and code proposal are done on the same installation just changing the branchs (master) created for the tests so everything else is constant.&lt;br /&gt;
&lt;br /&gt;
The Code proposal give similar results to the 1,9 version with a more precise handling of 0 as answer.&lt;br /&gt;
&lt;br /&gt;
TODO : Review the Code proposal , use as suggested $epsilon, ....&lt;br /&gt;
=Final Code proposal=&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    if ($this-&amp;gt;answer == 0.0){&lt;br /&gt;
         if($this-&amp;gt;tolerance == 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)){ // the 0&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         }&lt;br /&gt;
   } else {&lt;br /&gt;
         if($this-&amp;gt;tolerance === 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer) ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)* abs($this-&amp;gt;answer)){ &lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
         }     &lt;br /&gt;
   }         &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This &amp;quot;linear&amp;quot; code can be rewritten differently : &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
     if ($this-&amp;gt;answer == 0.0){&lt;br /&gt;
         if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)){ // the 0&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         }&lt;br /&gt;
   } else {&lt;br /&gt;
         if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)* abs($this-&amp;gt;answer)){ &lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
         }&lt;br /&gt;
   } &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
If we add &lt;br /&gt;
&lt;br /&gt;
    $epsilon = pow(10, -1 * ini_get(&#039;precision&#039;));&lt;br /&gt;
&lt;br /&gt;
then&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34924</id>
		<title>Question Engine 2:Numerical tolerances</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34924"/>
		<updated>2012-08-17T05:13:52Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: /* Final Code proposal */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Analysis of the various tolerances for numerical and calculated question type answer see (MDL-31837)&lt;br /&gt;
&lt;br /&gt;
In grading a numerical response, the (student) numerical value is compared to the answer numerical value.&lt;br /&gt;
&lt;br /&gt;
This comparison allow a tolerance that is associated with the answer and that can be expressed in various ways.&lt;br /&gt;
&lt;br /&gt;
For calculated question answers the tolerance can be of 3 different types: relative, nominal or geometric. &lt;br /&gt;
=Limits of real numbers in PHP=&lt;br /&gt;
&lt;br /&gt;
The following is from http://www.php.net/manual/en/language.types.float.php&lt;br /&gt;
&lt;br /&gt;
The size of a float is platform-dependent, although a maximum of ~1.8e308 with a precision of roughly 14 decimal digits is a common value (the 64 bit IEEE format).&lt;br /&gt;
&lt;br /&gt;
 Warning&lt;br /&gt;
 Floating point precision&lt;br /&gt;
&lt;br /&gt;
Floating point numbers have limited precision. Although it depends on the system, PHP typically uses the IEEE 754 double precision format, which will give a maximum relative error due to rounding in the order of 1.11e-16. Non elementary arithmetic operations may give larger errors, and, of course, error propagation must be considered when several operations are compounded.&lt;br /&gt;
&lt;br /&gt;
Additionally, rational numbers that are exactly representable as floating point numbers in base 10, like 0.1 or 0.7, do not have an exact representation as floating point numbers in base 2, which is used internally, no matter the size of the mantissa. Hence, they cannot be converted into their internal binary counterparts without a small loss of precision. This can lead to confusing results: for example, floor((0.1+0.7)*10) will usually return 7 instead of the expected 8, since the internal representation will be something like 7.9999999999999991118....&lt;br /&gt;
&lt;br /&gt;
So never trust floating number results to the last digit, and do not compare floating point numbers directly for equality. If higher precision is necessary, the arbitrary precision math functions and gmp functions are available.&lt;br /&gt;
&lt;br /&gt;
Since the internal representation is in base 2, 0 and 1 will have the same exponent so the precision ( i.e. init_get(&#039;precision&#039;) should have the same value.?&lt;br /&gt;
&lt;br /&gt;
....&lt;br /&gt;
=1,9 version=&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
function get_tolerance_interval(&amp;amp;$answer) {&lt;br /&gt;
        // No tolerance&lt;br /&gt;
        if (empty($answer-&amp;gt;tolerance)) {&lt;br /&gt;
            $answer-&amp;gt;tolerance = 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Calculate the interval of correct responses (min/max)&lt;br /&gt;
        if (!isset($answer-&amp;gt;tolerancetype)) {&lt;br /&gt;
            $answer-&amp;gt;tolerancetype = 2; // nominal&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make the&lt;br /&gt;
        // comparison work correctly. Otherwise seemingly equal values can yield&lt;br /&gt;
        // false. (fixes bug #3225)&lt;br /&gt;
        $tolerance = (float)$answer-&amp;gt;tolerance + (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;));&lt;br /&gt;
        switch ($answer-&amp;gt;tolerancetype) {&lt;br /&gt;
            case &#039;1&#039;: case &#039;relative&#039;:&lt;br /&gt;
                /// Recalculate the tolerance and fall through&lt;br /&gt;
                /// to the nominal case:&lt;br /&gt;
                $tolerance = $answer-&amp;gt;answer * $tolerance;&lt;br /&gt;
                // Do not fall through to the nominal case because the tiny fraction is a factor of the answer&lt;br /&gt;
                 $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;2&#039;: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                // $answer-&amp;gt;tolerance 0 or something else&lt;br /&gt;
                if ((float)$answer-&amp;gt;tolerance == 0.0  &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance ){&lt;br /&gt;
                    $tolerance = (float) (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) * abs((float)$answer-&amp;gt;answer) ; //tiny fraction&lt;br /&gt;
                } else if ((float)$answer-&amp;gt;tolerance != 0.0 &amp;amp;&amp;amp; abs((float)$answer-&amp;gt;tolerance) &amp;lt; abs((float)$answer-&amp;gt;answer) &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance){&lt;br /&gt;
                    $tolerance = (1+(&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) )* abs((float) $answer-&amp;gt;tolerance) ;//tiny fraction&lt;br /&gt;
               }&lt;br /&gt;
&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;3&#039;: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                $max = $answer-&amp;gt;answer * $quotient;&lt;br /&gt;
                $min = $answer-&amp;gt;answer / $quotient;&lt;br /&gt;
                break;&lt;br /&gt;
            default:&lt;br /&gt;
                error(&amp;quot;Unknown tolerance type $answer-&amp;gt;tolerancetype&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $answer-&amp;gt;min = $min;&lt;br /&gt;
        $answer-&amp;gt;max = $max;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 actual code=&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class qtype_numerical_answer extends question_answer {&lt;br /&gt;
    /** @var float allowable margin of error. */&lt;br /&gt;
    public $tolerance;&lt;br /&gt;
    /** @var integer|string see {@link get_tolerance_interval()} for the meaning of this value. */&lt;br /&gt;
    public $tolerancetype = 2;&lt;br /&gt;
&lt;br /&gt;
    public function __construct($id, $answer, $fraction, $feedback, $feedbackformat, $tolerance) {&lt;br /&gt;
        parent::__construct($id, $answer, $fraction, $feedback, $feedbackformat);&lt;br /&gt;
        $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_tolerance_interval() {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            throw new coding_exception(&#039;Cannot work out tolerance interval for answer *.&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make&lt;br /&gt;
        // the comparison work correctly, otherwise seemingly equal values can&lt;br /&gt;
        // yield false. See MDL-3225.&lt;br /&gt;
        $tolerance = (float) $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;));&lt;br /&gt;
&lt;br /&gt;
        switch ($this-&amp;gt;tolerancetype) {&lt;br /&gt;
            case 1: case &#039;relative&#039;:&lt;br /&gt;
                $range = abs($this-&amp;gt;answer) * $tolerance;&lt;br /&gt;
                return array($this-&amp;gt;answer - $range, $this-&amp;gt;answer + $range);&lt;br /&gt;
&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) *&lt;br /&gt;
                        max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&lt;br /&gt;
            case 3: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                return array($this-&amp;gt;answer / $quotient, $this-&amp;gt;answer * $quotient);&lt;br /&gt;
&lt;br /&gt;
            default:&lt;br /&gt;
                throw new coding_exception(&#039;Unknown tolerance type &#039; . $this-&amp;gt;tolerancetype);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function within_tolerance($value) {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
        list($min, $max) = $this-&amp;gt;get_tolerance_interval();&lt;br /&gt;
        return $min &amp;lt;= $value &amp;amp;&amp;amp; $value &amp;lt;= $max;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 vs 1,9 differences=&lt;br /&gt;
== case relative ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case geometric ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case nominal ==&lt;br /&gt;
The use of &lt;br /&gt;
 pow(10, -1 * ini_get(&#039;precision&#039;)) * max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
The &#039;tiny fraction&#039; part of the tolerance  is not related to the answer when the answer is less than 1. &lt;br /&gt;
&lt;br /&gt;
We should get back to the 1,9 equivalent code first by removing the max function &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The 1,9 code has a special treatment of the answer == 0 .&lt;br /&gt;
&lt;br /&gt;
Should we keep the code ?&lt;br /&gt;
&lt;br /&gt;
=== Answer is 0===&lt;br /&gt;
What is the precision of 0 ?&lt;br /&gt;
It cannot be 0 , it only can be the precision of the digital part of the number i.e.  pow(10, -1 * ini_get(&#039;precision&#039;)).&lt;br /&gt;
As a mather of fact the exponent part of 0 is the same one as 1 so its precision is the same.&lt;br /&gt;
We should not forget that the &amp;quot;turning point&amp;quot; (positive to negative)  of real number exponent value is 1 not 0.&lt;br /&gt;
&lt;br /&gt;
So to get the &amp;quot;tiny number&amp;quot; we should multiply the  pow(10, -1 * ini_get(&#039;precision&#039;)) by $this-&amp;gt;answer except when $this-&amp;gt;answer == 0 when it should be 1.&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 0,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;pow(10, -1 * ini_get(&#039;precision&#039;))=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
&lt;br /&gt;
=== Answer is NOT 0===&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;tiny part&amp;quot; should mostly be calculated as pow(10, -1 * ini_get(&#039;precision&#039;))*$answer&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 2,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;=pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))** $this-&amp;gt;answer ;&lt;br /&gt;
&lt;br /&gt;
=Code flow proposal=&lt;br /&gt;
&lt;br /&gt;
This code reflects the discussion although a more concise version could be built.&lt;br /&gt;
The proposal is somehow different from the 1,9 version as it includes the precision of the tolerance in the range.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    if ($this-&amp;gt;answer == 0.0){&lt;br /&gt;
         if($this-&amp;gt;tolerance == 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)){ // the 0&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         }&lt;br /&gt;
   } else {&lt;br /&gt;
         if($this-&amp;gt;tolerance === 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer) ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)* abs($this-&amp;gt;answer)){ &lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
         }     &lt;br /&gt;
   }         &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Tim&#039;s idea==&lt;br /&gt;
&lt;br /&gt;
I am wondering whether it works just change &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the 2.0 code to&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max($this-&amp;gt;tolerance, abs($this-&amp;gt;answer), pow(10, -1 * ini_get(&#039;precision&#039;)));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code might be nicer if we define $epsilon = pow(10, -1 * ini_get(&#039;precision&#039;)) at the start of the function.&lt;br /&gt;
&lt;br /&gt;
Finally, I would like to know what tests you propose to add to question/type/numerical/tests/answer_test.php in order to demonstrate that everything is working properly. In particular, what tests would you like to add that will fail with the current code, but which will pass once we have fixed this bug?&lt;br /&gt;
&lt;br /&gt;
--[[User:Tim Hunt|Tim Hunt]] 00:53, 16 August 2012 (WST)&lt;br /&gt;
==Pierre&#039;s comment==&lt;br /&gt;
Thanks for your code expert feedback...&lt;br /&gt;
&lt;br /&gt;
I am using a simple calculated question on 2,0 or a calculated question on 1,9  to test the various combinations with different answers and tolerances.&lt;br /&gt;
&lt;br /&gt;
The range (Min- Max ) is available directly.&lt;br /&gt;
&lt;br /&gt;
At first tests your proposal seems to be working.&lt;br /&gt;
&lt;br /&gt;
I will report here the results of various tests on 1,9, actual 2, your proposal and the more linear code.&lt;br /&gt;
&lt;br /&gt;
This should help us to choose which tests to use.&lt;br /&gt;
&lt;br /&gt;
[[User:Pierre Pichet|Pierre Pichet]] 12:38, 16 August 2012 (WST)&lt;br /&gt;
&lt;br /&gt;
=Tests results=&lt;br /&gt;
Types&lt;br /&gt;
* R :relative &lt;br /&gt;
*N  :nominal &lt;br /&gt;
*G  : geometric&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Answer!!Tolerance !!Type    !! 1,9 Min!! 1,9 Max!! Code Min !! Code Max!! 2,0 Min!! 2,0 Max!! Tim Min!! Tim Max&lt;br /&gt;
|-&lt;br /&gt;
|0          ||  0          ||  N      ||  0        ||  0    ||  -1.0E-14 ||  1.0E-14||  -1.0E-14  ||  1.0E-14  || -1.0E-28    ||  1.0E-28      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  1e-24    ||  N    || 0   || 0    ||  -1.0E-24 ||  1.0E-24||  -1.0000000001E-14   ||  +1.0000000001E-14   ||  -1.0001E-24    ||  1.0001E-24     &lt;br /&gt;
|-&lt;br /&gt;
|1e-20          ||  0   ||  N|| 9.9999999999999E-21  ||  1.0E-20    ||  9.9999999999999E-21 ||  1.0E-20||  -9.99999E-15   ||  1.000001E-14   || 9.9999999999999E-21    ||  1.0E-20     &lt;br /&gt;
|-&lt;br /&gt;
|1e-20          ||  1e-24    || N || 9.999E-21   ||  1.0001E-20|| 9.999E-21||1.0001E-20 ||  -9.999990001E-15   ||  1.0000010001E-14   ||  9.9989999E-21    ||  1.00010001E-20      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The tests on master, Tim proposal and code proposal are done on the same installation just changing the branchs (master) created for the tests so everything else is constant.&lt;br /&gt;
&lt;br /&gt;
The Code proposal give similar results to the 1,9 version with a more precise handling of 0 as answer.&lt;br /&gt;
&lt;br /&gt;
TODO : Review the Code proposal , use as suggested $epsilon, ....&lt;br /&gt;
=Final Code proposal=&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    if ($this-&amp;gt;answer == 0.0){&lt;br /&gt;
         if($this-&amp;gt;tolerance == 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)){ // the 0&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         }&lt;br /&gt;
   } else {&lt;br /&gt;
         if($this-&amp;gt;tolerance === 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer) ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)* abs($this-&amp;gt;answer)){ &lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
         }     &lt;br /&gt;
   }         &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This &amp;quot;linear&amp;quot; code can be rewritten differently : &lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    if ($this-&amp;gt;answer == 0.0){&lt;br /&gt;
         if($this-&amp;gt;tolerance == 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)){ // the 0&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         }&lt;br /&gt;
   } else {&lt;br /&gt;
         if($this-&amp;gt;tolerance === 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer) ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)* abs($this-&amp;gt;answer)){ &lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
         }     &lt;br /&gt;
   }         &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
     if ($this-&amp;gt;answer == 0.0){&lt;br /&gt;
         if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)){ // the 0&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         }&lt;br /&gt;
   } else {&lt;br /&gt;
         if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)* abs($this-&amp;gt;answer)){ &lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
         }&lt;br /&gt;
   } &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
If we add &lt;br /&gt;
&lt;br /&gt;
    $epsilon = pow(10, -1 * ini_get(&#039;precision&#039;));&lt;br /&gt;
&lt;br /&gt;
then&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34923</id>
		<title>Question Engine 2:Numerical tolerances</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34923"/>
		<updated>2012-08-17T05:05:23Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: /* Code flow proposal */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Analysis of the various tolerances for numerical and calculated question type answer see (MDL-31837)&lt;br /&gt;
&lt;br /&gt;
In grading a numerical response, the (student) numerical value is compared to the answer numerical value.&lt;br /&gt;
&lt;br /&gt;
This comparison allow a tolerance that is associated with the answer and that can be expressed in various ways.&lt;br /&gt;
&lt;br /&gt;
For calculated question answers the tolerance can be of 3 different types: relative, nominal or geometric. &lt;br /&gt;
=Limits of real numbers in PHP=&lt;br /&gt;
&lt;br /&gt;
The following is from http://www.php.net/manual/en/language.types.float.php&lt;br /&gt;
&lt;br /&gt;
The size of a float is platform-dependent, although a maximum of ~1.8e308 with a precision of roughly 14 decimal digits is a common value (the 64 bit IEEE format).&lt;br /&gt;
&lt;br /&gt;
 Warning&lt;br /&gt;
 Floating point precision&lt;br /&gt;
&lt;br /&gt;
Floating point numbers have limited precision. Although it depends on the system, PHP typically uses the IEEE 754 double precision format, which will give a maximum relative error due to rounding in the order of 1.11e-16. Non elementary arithmetic operations may give larger errors, and, of course, error propagation must be considered when several operations are compounded.&lt;br /&gt;
&lt;br /&gt;
Additionally, rational numbers that are exactly representable as floating point numbers in base 10, like 0.1 or 0.7, do not have an exact representation as floating point numbers in base 2, which is used internally, no matter the size of the mantissa. Hence, they cannot be converted into their internal binary counterparts without a small loss of precision. This can lead to confusing results: for example, floor((0.1+0.7)*10) will usually return 7 instead of the expected 8, since the internal representation will be something like 7.9999999999999991118....&lt;br /&gt;
&lt;br /&gt;
So never trust floating number results to the last digit, and do not compare floating point numbers directly for equality. If higher precision is necessary, the arbitrary precision math functions and gmp functions are available.&lt;br /&gt;
&lt;br /&gt;
Since the internal representation is in base 2, 0 and 1 will have the same exponent so the precision ( i.e. init_get(&#039;precision&#039;) should have the same value.?&lt;br /&gt;
&lt;br /&gt;
....&lt;br /&gt;
=1,9 version=&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
function get_tolerance_interval(&amp;amp;$answer) {&lt;br /&gt;
        // No tolerance&lt;br /&gt;
        if (empty($answer-&amp;gt;tolerance)) {&lt;br /&gt;
            $answer-&amp;gt;tolerance = 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Calculate the interval of correct responses (min/max)&lt;br /&gt;
        if (!isset($answer-&amp;gt;tolerancetype)) {&lt;br /&gt;
            $answer-&amp;gt;tolerancetype = 2; // nominal&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make the&lt;br /&gt;
        // comparison work correctly. Otherwise seemingly equal values can yield&lt;br /&gt;
        // false. (fixes bug #3225)&lt;br /&gt;
        $tolerance = (float)$answer-&amp;gt;tolerance + (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;));&lt;br /&gt;
        switch ($answer-&amp;gt;tolerancetype) {&lt;br /&gt;
            case &#039;1&#039;: case &#039;relative&#039;:&lt;br /&gt;
                /// Recalculate the tolerance and fall through&lt;br /&gt;
                /// to the nominal case:&lt;br /&gt;
                $tolerance = $answer-&amp;gt;answer * $tolerance;&lt;br /&gt;
                // Do not fall through to the nominal case because the tiny fraction is a factor of the answer&lt;br /&gt;
                 $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;2&#039;: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                // $answer-&amp;gt;tolerance 0 or something else&lt;br /&gt;
                if ((float)$answer-&amp;gt;tolerance == 0.0  &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance ){&lt;br /&gt;
                    $tolerance = (float) (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) * abs((float)$answer-&amp;gt;answer) ; //tiny fraction&lt;br /&gt;
                } else if ((float)$answer-&amp;gt;tolerance != 0.0 &amp;amp;&amp;amp; abs((float)$answer-&amp;gt;tolerance) &amp;lt; abs((float)$answer-&amp;gt;answer) &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance){&lt;br /&gt;
                    $tolerance = (1+(&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) )* abs((float) $answer-&amp;gt;tolerance) ;//tiny fraction&lt;br /&gt;
               }&lt;br /&gt;
&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;3&#039;: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                $max = $answer-&amp;gt;answer * $quotient;&lt;br /&gt;
                $min = $answer-&amp;gt;answer / $quotient;&lt;br /&gt;
                break;&lt;br /&gt;
            default:&lt;br /&gt;
                error(&amp;quot;Unknown tolerance type $answer-&amp;gt;tolerancetype&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $answer-&amp;gt;min = $min;&lt;br /&gt;
        $answer-&amp;gt;max = $max;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 actual code=&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class qtype_numerical_answer extends question_answer {&lt;br /&gt;
    /** @var float allowable margin of error. */&lt;br /&gt;
    public $tolerance;&lt;br /&gt;
    /** @var integer|string see {@link get_tolerance_interval()} for the meaning of this value. */&lt;br /&gt;
    public $tolerancetype = 2;&lt;br /&gt;
&lt;br /&gt;
    public function __construct($id, $answer, $fraction, $feedback, $feedbackformat, $tolerance) {&lt;br /&gt;
        parent::__construct($id, $answer, $fraction, $feedback, $feedbackformat);&lt;br /&gt;
        $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_tolerance_interval() {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            throw new coding_exception(&#039;Cannot work out tolerance interval for answer *.&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make&lt;br /&gt;
        // the comparison work correctly, otherwise seemingly equal values can&lt;br /&gt;
        // yield false. See MDL-3225.&lt;br /&gt;
        $tolerance = (float) $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;));&lt;br /&gt;
&lt;br /&gt;
        switch ($this-&amp;gt;tolerancetype) {&lt;br /&gt;
            case 1: case &#039;relative&#039;:&lt;br /&gt;
                $range = abs($this-&amp;gt;answer) * $tolerance;&lt;br /&gt;
                return array($this-&amp;gt;answer - $range, $this-&amp;gt;answer + $range);&lt;br /&gt;
&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) *&lt;br /&gt;
                        max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&lt;br /&gt;
            case 3: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                return array($this-&amp;gt;answer / $quotient, $this-&amp;gt;answer * $quotient);&lt;br /&gt;
&lt;br /&gt;
            default:&lt;br /&gt;
                throw new coding_exception(&#039;Unknown tolerance type &#039; . $this-&amp;gt;tolerancetype);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function within_tolerance($value) {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
        list($min, $max) = $this-&amp;gt;get_tolerance_interval();&lt;br /&gt;
        return $min &amp;lt;= $value &amp;amp;&amp;amp; $value &amp;lt;= $max;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 vs 1,9 differences=&lt;br /&gt;
== case relative ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case geometric ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case nominal ==&lt;br /&gt;
The use of &lt;br /&gt;
 pow(10, -1 * ini_get(&#039;precision&#039;)) * max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
The &#039;tiny fraction&#039; part of the tolerance  is not related to the answer when the answer is less than 1. &lt;br /&gt;
&lt;br /&gt;
We should get back to the 1,9 equivalent code first by removing the max function &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The 1,9 code has a special treatment of the answer == 0 .&lt;br /&gt;
&lt;br /&gt;
Should we keep the code ?&lt;br /&gt;
&lt;br /&gt;
=== Answer is 0===&lt;br /&gt;
What is the precision of 0 ?&lt;br /&gt;
It cannot be 0 , it only can be the precision of the digital part of the number i.e.  pow(10, -1 * ini_get(&#039;precision&#039;)).&lt;br /&gt;
As a mather of fact the exponent part of 0 is the same one as 1 so its precision is the same.&lt;br /&gt;
We should not forget that the &amp;quot;turning point&amp;quot; (positive to negative)  of real number exponent value is 1 not 0.&lt;br /&gt;
&lt;br /&gt;
So to get the &amp;quot;tiny number&amp;quot; we should multiply the  pow(10, -1 * ini_get(&#039;precision&#039;)) by $this-&amp;gt;answer except when $this-&amp;gt;answer == 0 when it should be 1.&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 0,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;pow(10, -1 * ini_get(&#039;precision&#039;))=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
&lt;br /&gt;
=== Answer is NOT 0===&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;tiny part&amp;quot; should mostly be calculated as pow(10, -1 * ini_get(&#039;precision&#039;))*$answer&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 2,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;=pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))** $this-&amp;gt;answer ;&lt;br /&gt;
&lt;br /&gt;
=Code flow proposal=&lt;br /&gt;
&lt;br /&gt;
This code reflects the discussion although a more concise version could be built.&lt;br /&gt;
The proposal is somehow different from the 1,9 version as it includes the precision of the tolerance in the range.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    if ($this-&amp;gt;answer == 0.0){&lt;br /&gt;
         if($this-&amp;gt;tolerance == 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)){ // the 0&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         }&lt;br /&gt;
   } else {&lt;br /&gt;
         if($this-&amp;gt;tolerance === 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer) ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)* abs($this-&amp;gt;answer)){ &lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
         }     &lt;br /&gt;
   }         &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Tim&#039;s idea==&lt;br /&gt;
&lt;br /&gt;
I am wondering whether it works just change &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the 2.0 code to&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max($this-&amp;gt;tolerance, abs($this-&amp;gt;answer), pow(10, -1 * ini_get(&#039;precision&#039;)));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code might be nicer if we define $epsilon = pow(10, -1 * ini_get(&#039;precision&#039;)) at the start of the function.&lt;br /&gt;
&lt;br /&gt;
Finally, I would like to know what tests you propose to add to question/type/numerical/tests/answer_test.php in order to demonstrate that everything is working properly. In particular, what tests would you like to add that will fail with the current code, but which will pass once we have fixed this bug?&lt;br /&gt;
&lt;br /&gt;
--[[User:Tim Hunt|Tim Hunt]] 00:53, 16 August 2012 (WST)&lt;br /&gt;
==Pierre&#039;s comment==&lt;br /&gt;
Thanks for your code expert feedback...&lt;br /&gt;
&lt;br /&gt;
I am using a simple calculated question on 2,0 or a calculated question on 1,9  to test the various combinations with different answers and tolerances.&lt;br /&gt;
&lt;br /&gt;
The range (Min- Max ) is available directly.&lt;br /&gt;
&lt;br /&gt;
At first tests your proposal seems to be working.&lt;br /&gt;
&lt;br /&gt;
I will report here the results of various tests on 1,9, actual 2, your proposal and the more linear code.&lt;br /&gt;
&lt;br /&gt;
This should help us to choose which tests to use.&lt;br /&gt;
&lt;br /&gt;
[[User:Pierre Pichet|Pierre Pichet]] 12:38, 16 August 2012 (WST)&lt;br /&gt;
&lt;br /&gt;
=Tests results=&lt;br /&gt;
Types&lt;br /&gt;
* R :relative &lt;br /&gt;
*N  :nominal &lt;br /&gt;
*G  : geometric&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Answer!!Tolerance !!Type    !! 1,9 Min!! 1,9 Max!! Code Min !! Code Max!! 2,0 Min!! 2,0 Max!! Tim Min!! Tim Max&lt;br /&gt;
|-&lt;br /&gt;
|0          ||  0          ||  N      ||  0        ||  0    ||  -1.0E-14 ||  1.0E-14||  -1.0E-14  ||  1.0E-14  || -1.0E-28    ||  1.0E-28      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  1e-24    ||  N    || 0   || 0    ||  -1.0E-24 ||  1.0E-24||  -1.0000000001E-14   ||  +1.0000000001E-14   ||  -1.0001E-24    ||  1.0001E-24     &lt;br /&gt;
|-&lt;br /&gt;
|1e-20          ||  0   ||  N|| 9.9999999999999E-21  ||  1.0E-20    ||  9.9999999999999E-21 ||  1.0E-20||  -9.99999E-15   ||  1.000001E-14   || 9.9999999999999E-21    ||  1.0E-20     &lt;br /&gt;
|-&lt;br /&gt;
|1e-20          ||  1e-24    || N || 9.999E-21   ||  1.0001E-20|| 9.999E-21||1.0001E-20 ||  -9.999990001E-15   ||  1.0000010001E-14   ||  9.9989999E-21    ||  1.00010001E-20      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The tests on master, Tim proposal and code proposal are done on the same installation just changing the branchs (master) created for the tests so everything else is constant.&lt;br /&gt;
&lt;br /&gt;
The Code proposal give similar results to the 1,9 version with a more precise handling of 0 as answer.&lt;br /&gt;
&lt;br /&gt;
TODO : Review the Code proposal , use as suggested $epsilon, ....&lt;br /&gt;
=Final Code proposal=&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    if ($this-&amp;gt;answer == 0.0){&lt;br /&gt;
         if($this-&amp;gt;tolerance == 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)){ // the 0&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         }&lt;br /&gt;
   } else {&lt;br /&gt;
         if($this-&amp;gt;tolerance === 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;answer ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)* abs($this-&amp;gt;answer)){ &lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
         }     &lt;br /&gt;
   }         &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This &amp;quot;linear&amp;quot; code can be rewritten differently  $this-&amp;gt;answer == 0, &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If we add &lt;br /&gt;
&lt;br /&gt;
 $epsilon = pow(10, -1 * ini_get(&#039;precision&#039;));&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34922</id>
		<title>Question Engine 2:Numerical tolerances</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34922"/>
		<updated>2012-08-17T05:04:31Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Analysis of the various tolerances for numerical and calculated question type answer see (MDL-31837)&lt;br /&gt;
&lt;br /&gt;
In grading a numerical response, the (student) numerical value is compared to the answer numerical value.&lt;br /&gt;
&lt;br /&gt;
This comparison allow a tolerance that is associated with the answer and that can be expressed in various ways.&lt;br /&gt;
&lt;br /&gt;
For calculated question answers the tolerance can be of 3 different types: relative, nominal or geometric. &lt;br /&gt;
=Limits of real numbers in PHP=&lt;br /&gt;
&lt;br /&gt;
The following is from http://www.php.net/manual/en/language.types.float.php&lt;br /&gt;
&lt;br /&gt;
The size of a float is platform-dependent, although a maximum of ~1.8e308 with a precision of roughly 14 decimal digits is a common value (the 64 bit IEEE format).&lt;br /&gt;
&lt;br /&gt;
 Warning&lt;br /&gt;
 Floating point precision&lt;br /&gt;
&lt;br /&gt;
Floating point numbers have limited precision. Although it depends on the system, PHP typically uses the IEEE 754 double precision format, which will give a maximum relative error due to rounding in the order of 1.11e-16. Non elementary arithmetic operations may give larger errors, and, of course, error propagation must be considered when several operations are compounded.&lt;br /&gt;
&lt;br /&gt;
Additionally, rational numbers that are exactly representable as floating point numbers in base 10, like 0.1 or 0.7, do not have an exact representation as floating point numbers in base 2, which is used internally, no matter the size of the mantissa. Hence, they cannot be converted into their internal binary counterparts without a small loss of precision. This can lead to confusing results: for example, floor((0.1+0.7)*10) will usually return 7 instead of the expected 8, since the internal representation will be something like 7.9999999999999991118....&lt;br /&gt;
&lt;br /&gt;
So never trust floating number results to the last digit, and do not compare floating point numbers directly for equality. If higher precision is necessary, the arbitrary precision math functions and gmp functions are available.&lt;br /&gt;
&lt;br /&gt;
Since the internal representation is in base 2, 0 and 1 will have the same exponent so the precision ( i.e. init_get(&#039;precision&#039;) should have the same value.?&lt;br /&gt;
&lt;br /&gt;
....&lt;br /&gt;
=1,9 version=&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
function get_tolerance_interval(&amp;amp;$answer) {&lt;br /&gt;
        // No tolerance&lt;br /&gt;
        if (empty($answer-&amp;gt;tolerance)) {&lt;br /&gt;
            $answer-&amp;gt;tolerance = 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Calculate the interval of correct responses (min/max)&lt;br /&gt;
        if (!isset($answer-&amp;gt;tolerancetype)) {&lt;br /&gt;
            $answer-&amp;gt;tolerancetype = 2; // nominal&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make the&lt;br /&gt;
        // comparison work correctly. Otherwise seemingly equal values can yield&lt;br /&gt;
        // false. (fixes bug #3225)&lt;br /&gt;
        $tolerance = (float)$answer-&amp;gt;tolerance + (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;));&lt;br /&gt;
        switch ($answer-&amp;gt;tolerancetype) {&lt;br /&gt;
            case &#039;1&#039;: case &#039;relative&#039;:&lt;br /&gt;
                /// Recalculate the tolerance and fall through&lt;br /&gt;
                /// to the nominal case:&lt;br /&gt;
                $tolerance = $answer-&amp;gt;answer * $tolerance;&lt;br /&gt;
                // Do not fall through to the nominal case because the tiny fraction is a factor of the answer&lt;br /&gt;
                 $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;2&#039;: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                // $answer-&amp;gt;tolerance 0 or something else&lt;br /&gt;
                if ((float)$answer-&amp;gt;tolerance == 0.0  &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance ){&lt;br /&gt;
                    $tolerance = (float) (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) * abs((float)$answer-&amp;gt;answer) ; //tiny fraction&lt;br /&gt;
                } else if ((float)$answer-&amp;gt;tolerance != 0.0 &amp;amp;&amp;amp; abs((float)$answer-&amp;gt;tolerance) &amp;lt; abs((float)$answer-&amp;gt;answer) &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance){&lt;br /&gt;
                    $tolerance = (1+(&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) )* abs((float) $answer-&amp;gt;tolerance) ;//tiny fraction&lt;br /&gt;
               }&lt;br /&gt;
&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;3&#039;: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                $max = $answer-&amp;gt;answer * $quotient;&lt;br /&gt;
                $min = $answer-&amp;gt;answer / $quotient;&lt;br /&gt;
                break;&lt;br /&gt;
            default:&lt;br /&gt;
                error(&amp;quot;Unknown tolerance type $answer-&amp;gt;tolerancetype&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $answer-&amp;gt;min = $min;&lt;br /&gt;
        $answer-&amp;gt;max = $max;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 actual code=&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class qtype_numerical_answer extends question_answer {&lt;br /&gt;
    /** @var float allowable margin of error. */&lt;br /&gt;
    public $tolerance;&lt;br /&gt;
    /** @var integer|string see {@link get_tolerance_interval()} for the meaning of this value. */&lt;br /&gt;
    public $tolerancetype = 2;&lt;br /&gt;
&lt;br /&gt;
    public function __construct($id, $answer, $fraction, $feedback, $feedbackformat, $tolerance) {&lt;br /&gt;
        parent::__construct($id, $answer, $fraction, $feedback, $feedbackformat);&lt;br /&gt;
        $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_tolerance_interval() {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            throw new coding_exception(&#039;Cannot work out tolerance interval for answer *.&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make&lt;br /&gt;
        // the comparison work correctly, otherwise seemingly equal values can&lt;br /&gt;
        // yield false. See MDL-3225.&lt;br /&gt;
        $tolerance = (float) $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;));&lt;br /&gt;
&lt;br /&gt;
        switch ($this-&amp;gt;tolerancetype) {&lt;br /&gt;
            case 1: case &#039;relative&#039;:&lt;br /&gt;
                $range = abs($this-&amp;gt;answer) * $tolerance;&lt;br /&gt;
                return array($this-&amp;gt;answer - $range, $this-&amp;gt;answer + $range);&lt;br /&gt;
&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) *&lt;br /&gt;
                        max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&lt;br /&gt;
            case 3: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                return array($this-&amp;gt;answer / $quotient, $this-&amp;gt;answer * $quotient);&lt;br /&gt;
&lt;br /&gt;
            default:&lt;br /&gt;
                throw new coding_exception(&#039;Unknown tolerance type &#039; . $this-&amp;gt;tolerancetype);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function within_tolerance($value) {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
        list($min, $max) = $this-&amp;gt;get_tolerance_interval();&lt;br /&gt;
        return $min &amp;lt;= $value &amp;amp;&amp;amp; $value &amp;lt;= $max;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 vs 1,9 differences=&lt;br /&gt;
== case relative ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case geometric ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case nominal ==&lt;br /&gt;
The use of &lt;br /&gt;
 pow(10, -1 * ini_get(&#039;precision&#039;)) * max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
The &#039;tiny fraction&#039; part of the tolerance  is not related to the answer when the answer is less than 1. &lt;br /&gt;
&lt;br /&gt;
We should get back to the 1,9 equivalent code first by removing the max function &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The 1,9 code has a special treatment of the answer == 0 .&lt;br /&gt;
&lt;br /&gt;
Should we keep the code ?&lt;br /&gt;
&lt;br /&gt;
=== Answer is 0===&lt;br /&gt;
What is the precision of 0 ?&lt;br /&gt;
It cannot be 0 , it only can be the precision of the digital part of the number i.e.  pow(10, -1 * ini_get(&#039;precision&#039;)).&lt;br /&gt;
As a mather of fact the exponent part of 0 is the same one as 1 so its precision is the same.&lt;br /&gt;
We should not forget that the &amp;quot;turning point&amp;quot; (positive to negative)  of real number exponent value is 1 not 0.&lt;br /&gt;
&lt;br /&gt;
So to get the &amp;quot;tiny number&amp;quot; we should multiply the  pow(10, -1 * ini_get(&#039;precision&#039;)) by $this-&amp;gt;answer except when $this-&amp;gt;answer == 0 when it should be 1.&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 0,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;pow(10, -1 * ini_get(&#039;precision&#039;))=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
&lt;br /&gt;
=== Answer is NOT 0===&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;tiny part&amp;quot; should mostly be calculated as pow(10, -1 * ini_get(&#039;precision&#039;))*$answer&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 2,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;=pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))** $this-&amp;gt;answer ;&lt;br /&gt;
&lt;br /&gt;
=Code flow proposal=&lt;br /&gt;
&lt;br /&gt;
This code reflects the discussion although a more concise version could be built.&lt;br /&gt;
The proposal is somehow different from the 1,9 version as it includes the precision of the tolerance in the range.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    if ($this-&amp;gt;answer == 0.0){&lt;br /&gt;
         if($this-&amp;gt;tolerance == 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)){ // the 0&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         }&lt;br /&gt;
   } else {&lt;br /&gt;
         if($this-&amp;gt;tolerance === 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;answer ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)* abs($this-&amp;gt;answer)){ &lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
         }     &lt;br /&gt;
   }         &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Tim&#039;s idea==&lt;br /&gt;
&lt;br /&gt;
I am wondering whether it works just change &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the 2.0 code to&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max($this-&amp;gt;tolerance, abs($this-&amp;gt;answer), pow(10, -1 * ini_get(&#039;precision&#039;)));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code might be nicer if we define $epsilon = pow(10, -1 * ini_get(&#039;precision&#039;)) at the start of the function.&lt;br /&gt;
&lt;br /&gt;
Finally, I would like to know what tests you propose to add to question/type/numerical/tests/answer_test.php in order to demonstrate that everything is working properly. In particular, what tests would you like to add that will fail with the current code, but which will pass once we have fixed this bug?&lt;br /&gt;
&lt;br /&gt;
--[[User:Tim Hunt|Tim Hunt]] 00:53, 16 August 2012 (WST)&lt;br /&gt;
==Pierre&#039;s comment==&lt;br /&gt;
Thanks for your code expert feedback...&lt;br /&gt;
&lt;br /&gt;
I am using a simple calculated question on 2,0 or a calculated question on 1,9  to test the various combinations with different answers and tolerances.&lt;br /&gt;
&lt;br /&gt;
The range (Min- Max ) is available directly.&lt;br /&gt;
&lt;br /&gt;
At first tests your proposal seems to be working.&lt;br /&gt;
&lt;br /&gt;
I will report here the results of various tests on 1,9, actual 2, your proposal and the more linear code.&lt;br /&gt;
&lt;br /&gt;
This should help us to choose which tests to use.&lt;br /&gt;
&lt;br /&gt;
[[User:Pierre Pichet|Pierre Pichet]] 12:38, 16 August 2012 (WST)&lt;br /&gt;
=Tests results=&lt;br /&gt;
Types&lt;br /&gt;
* R :relative &lt;br /&gt;
*N  :nominal &lt;br /&gt;
*G  : geometric&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Answer!!Tolerance !!Type    !! 1,9 Min!! 1,9 Max!! Code Min !! Code Max!! 2,0 Min!! 2,0 Max!! Tim Min!! Tim Max&lt;br /&gt;
|-&lt;br /&gt;
|0          ||  0          ||  N      ||  0        ||  0    ||  -1.0E-14 ||  1.0E-14||  -1.0E-14  ||  1.0E-14  || -1.0E-28    ||  1.0E-28      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  1e-24    ||  N    || 0   || 0    ||  -1.0E-24 ||  1.0E-24||  -1.0000000001E-14   ||  +1.0000000001E-14   ||  -1.0001E-24    ||  1.0001E-24     &lt;br /&gt;
|-&lt;br /&gt;
|1e-20          ||  0   ||  N|| 9.9999999999999E-21  ||  1.0E-20    ||  9.9999999999999E-21 ||  1.0E-20||  -9.99999E-15   ||  1.000001E-14   || 9.9999999999999E-21    ||  1.0E-20     &lt;br /&gt;
|-&lt;br /&gt;
|1e-20          ||  1e-24    || N || 9.999E-21   ||  1.0001E-20|| 9.999E-21||1.0001E-20 ||  -9.999990001E-15   ||  1.0000010001E-14   ||  9.9989999E-21    ||  1.00010001E-20      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The tests on master, Tim proposal and code proposal are done on the same installation just changing the branchs (master) created for the tests so everything else is constant.&lt;br /&gt;
&lt;br /&gt;
The Code proposal give similar results to the 1,9 version with a more precise handling of 0 as answer.&lt;br /&gt;
&lt;br /&gt;
TODO : Review the Code proposal , use as suggested $epsilon, ....&lt;br /&gt;
=Final Code proposal=&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    if ($this-&amp;gt;answer == 0.0){&lt;br /&gt;
         if($this-&amp;gt;tolerance == 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)){ // the 0&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         }&lt;br /&gt;
   } else {&lt;br /&gt;
         if($this-&amp;gt;tolerance === 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;answer ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)* abs($this-&amp;gt;answer)){ &lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
         }     &lt;br /&gt;
   }         &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This &amp;quot;linear&amp;quot; code can be rewritten differently  $this-&amp;gt;answer == 0, &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If we add &lt;br /&gt;
&lt;br /&gt;
 $epsilon = pow(10, -1 * ini_get(&#039;precision&#039;));&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34921</id>
		<title>Question Engine 2:Numerical tolerances</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34921"/>
		<updated>2012-08-17T04:52:13Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: /* Tests results */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Analysis of the various tolerances for numerical and calculated question type answer see (MDL-31837)&lt;br /&gt;
&lt;br /&gt;
In grading a numerical response, the (student) numerical value is compared to the answer numerical value.&lt;br /&gt;
&lt;br /&gt;
This comparison allow a tolerance that is associated with the answer and that can be expressed in various ways.&lt;br /&gt;
&lt;br /&gt;
For calculated question answers the tolerance can be of 3 different types: relative, nominal or geometric. &lt;br /&gt;
=Limits of real numbers in PHP=&lt;br /&gt;
&lt;br /&gt;
The following is from http://www.php.net/manual/en/language.types.float.php&lt;br /&gt;
&lt;br /&gt;
The size of a float is platform-dependent, although a maximum of ~1.8e308 with a precision of roughly 14 decimal digits is a common value (the 64 bit IEEE format).&lt;br /&gt;
&lt;br /&gt;
 Warning&lt;br /&gt;
 Floating point precision&lt;br /&gt;
&lt;br /&gt;
Floating point numbers have limited precision. Although it depends on the system, PHP typically uses the IEEE 754 double precision format, which will give a maximum relative error due to rounding in the order of 1.11e-16. Non elementary arithmetic operations may give larger errors, and, of course, error propagation must be considered when several operations are compounded.&lt;br /&gt;
&lt;br /&gt;
Additionally, rational numbers that are exactly representable as floating point numbers in base 10, like 0.1 or 0.7, do not have an exact representation as floating point numbers in base 2, which is used internally, no matter the size of the mantissa. Hence, they cannot be converted into their internal binary counterparts without a small loss of precision. This can lead to confusing results: for example, floor((0.1+0.7)*10) will usually return 7 instead of the expected 8, since the internal representation will be something like 7.9999999999999991118....&lt;br /&gt;
&lt;br /&gt;
So never trust floating number results to the last digit, and do not compare floating point numbers directly for equality. If higher precision is necessary, the arbitrary precision math functions and gmp functions are available.&lt;br /&gt;
&lt;br /&gt;
Since the internal representation is in base 2, 0 and 1 will have the same exponent so the precision ( i.e. init_get(&#039;precision&#039;) should have the same value.?&lt;br /&gt;
&lt;br /&gt;
....&lt;br /&gt;
=1,9 version=&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
function get_tolerance_interval(&amp;amp;$answer) {&lt;br /&gt;
        // No tolerance&lt;br /&gt;
        if (empty($answer-&amp;gt;tolerance)) {&lt;br /&gt;
            $answer-&amp;gt;tolerance = 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Calculate the interval of correct responses (min/max)&lt;br /&gt;
        if (!isset($answer-&amp;gt;tolerancetype)) {&lt;br /&gt;
            $answer-&amp;gt;tolerancetype = 2; // nominal&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make the&lt;br /&gt;
        // comparison work correctly. Otherwise seemingly equal values can yield&lt;br /&gt;
        // false. (fixes bug #3225)&lt;br /&gt;
        $tolerance = (float)$answer-&amp;gt;tolerance + (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;));&lt;br /&gt;
        switch ($answer-&amp;gt;tolerancetype) {&lt;br /&gt;
            case &#039;1&#039;: case &#039;relative&#039;:&lt;br /&gt;
                /// Recalculate the tolerance and fall through&lt;br /&gt;
                /// to the nominal case:&lt;br /&gt;
                $tolerance = $answer-&amp;gt;answer * $tolerance;&lt;br /&gt;
                // Do not fall through to the nominal case because the tiny fraction is a factor of the answer&lt;br /&gt;
                 $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;2&#039;: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                // $answer-&amp;gt;tolerance 0 or something else&lt;br /&gt;
                if ((float)$answer-&amp;gt;tolerance == 0.0  &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance ){&lt;br /&gt;
                    $tolerance = (float) (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) * abs((float)$answer-&amp;gt;answer) ; //tiny fraction&lt;br /&gt;
                } else if ((float)$answer-&amp;gt;tolerance != 0.0 &amp;amp;&amp;amp; abs((float)$answer-&amp;gt;tolerance) &amp;lt; abs((float)$answer-&amp;gt;answer) &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance){&lt;br /&gt;
                    $tolerance = (1+(&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) )* abs((float) $answer-&amp;gt;tolerance) ;//tiny fraction&lt;br /&gt;
               }&lt;br /&gt;
&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;3&#039;: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                $max = $answer-&amp;gt;answer * $quotient;&lt;br /&gt;
                $min = $answer-&amp;gt;answer / $quotient;&lt;br /&gt;
                break;&lt;br /&gt;
            default:&lt;br /&gt;
                error(&amp;quot;Unknown tolerance type $answer-&amp;gt;tolerancetype&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $answer-&amp;gt;min = $min;&lt;br /&gt;
        $answer-&amp;gt;max = $max;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 actual code=&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class qtype_numerical_answer extends question_answer {&lt;br /&gt;
    /** @var float allowable margin of error. */&lt;br /&gt;
    public $tolerance;&lt;br /&gt;
    /** @var integer|string see {@link get_tolerance_interval()} for the meaning of this value. */&lt;br /&gt;
    public $tolerancetype = 2;&lt;br /&gt;
&lt;br /&gt;
    public function __construct($id, $answer, $fraction, $feedback, $feedbackformat, $tolerance) {&lt;br /&gt;
        parent::__construct($id, $answer, $fraction, $feedback, $feedbackformat);&lt;br /&gt;
        $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_tolerance_interval() {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            throw new coding_exception(&#039;Cannot work out tolerance interval for answer *.&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make&lt;br /&gt;
        // the comparison work correctly, otherwise seemingly equal values can&lt;br /&gt;
        // yield false. See MDL-3225.&lt;br /&gt;
        $tolerance = (float) $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;));&lt;br /&gt;
&lt;br /&gt;
        switch ($this-&amp;gt;tolerancetype) {&lt;br /&gt;
            case 1: case &#039;relative&#039;:&lt;br /&gt;
                $range = abs($this-&amp;gt;answer) * $tolerance;&lt;br /&gt;
                return array($this-&amp;gt;answer - $range, $this-&amp;gt;answer + $range);&lt;br /&gt;
&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) *&lt;br /&gt;
                        max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&lt;br /&gt;
            case 3: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                return array($this-&amp;gt;answer / $quotient, $this-&amp;gt;answer * $quotient);&lt;br /&gt;
&lt;br /&gt;
            default:&lt;br /&gt;
                throw new coding_exception(&#039;Unknown tolerance type &#039; . $this-&amp;gt;tolerancetype);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function within_tolerance($value) {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
        list($min, $max) = $this-&amp;gt;get_tolerance_interval();&lt;br /&gt;
        return $min &amp;lt;= $value &amp;amp;&amp;amp; $value &amp;lt;= $max;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 vs 1,9 differences=&lt;br /&gt;
== case relative ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case geometric ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case nominal ==&lt;br /&gt;
The use of &lt;br /&gt;
 pow(10, -1 * ini_get(&#039;precision&#039;)) * max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
The &#039;tiny fraction&#039; part of the tolerance  is not related to the answer when the answer is less than 1. &lt;br /&gt;
&lt;br /&gt;
We should get back to the 1,9 equivalent code first by removing the max function &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The 1,9 code has a special treatment of the answer == 0 .&lt;br /&gt;
&lt;br /&gt;
Should we keep the code ?&lt;br /&gt;
&lt;br /&gt;
=== Answer is 0===&lt;br /&gt;
What is the precision of 0 ?&lt;br /&gt;
It cannot be 0 , it only can be the precision of the digital part of the number i.e.  pow(10, -1 * ini_get(&#039;precision&#039;)).&lt;br /&gt;
As a mather of fact the exponent part of 0 is the same one as 1 so its precision is the same.&lt;br /&gt;
We should not forget that the &amp;quot;turning point&amp;quot; (positive to negative)  of real number exponent value is 1 not 0.&lt;br /&gt;
&lt;br /&gt;
So to get the &amp;quot;tiny number&amp;quot; we should multiply the  pow(10, -1 * ini_get(&#039;precision&#039;)) by $this-&amp;gt;answer except when $this-&amp;gt;answer == 0 when it should be 1.&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 0,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;pow(10, -1 * ini_get(&#039;precision&#039;))=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
&lt;br /&gt;
=== Answer is NOT 0===&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;tiny part&amp;quot; should mostly be calculated as pow(10, -1 * ini_get(&#039;precision&#039;))*$answer&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 2,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;=pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))** $this-&amp;gt;answer ;&lt;br /&gt;
&lt;br /&gt;
=Code flow proposal=&lt;br /&gt;
&lt;br /&gt;
This code reflects the discussion although a more concise version could be built.&lt;br /&gt;
The proposal is somehow different from the 1,9 version as it includes the precision of the tolerance in the range.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    if ($this-&amp;gt;answer == 0.0){&lt;br /&gt;
         if($this-&amp;gt;tolerance == 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)){ // the 0&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         }&lt;br /&gt;
   } else {&lt;br /&gt;
         if($this-&amp;gt;tolerance === 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;answer ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)* abs($this-&amp;gt;answer)){ &lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
         }     &lt;br /&gt;
   }         &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Tim&#039;s idea==&lt;br /&gt;
&lt;br /&gt;
I am wondering whether it works just change &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the 2.0 code to&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max($this-&amp;gt;tolerance, abs($this-&amp;gt;answer), pow(10, -1 * ini_get(&#039;precision&#039;)));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code might be nicer if we define $epsilon = pow(10, -1 * ini_get(&#039;precision&#039;)) at the start of the function.&lt;br /&gt;
&lt;br /&gt;
Finally, I would like to know what tests you propose to add to question/type/numerical/tests/answer_test.php in order to demonstrate that everything is working properly. In particular, what tests would you like to add that will fail with the current code, but which will pass once we have fixed this bug?&lt;br /&gt;
&lt;br /&gt;
--[[User:Tim Hunt|Tim Hunt]] 00:53, 16 August 2012 (WST)&lt;br /&gt;
==Pierre&#039;s comment==&lt;br /&gt;
Thanks for your code expert feedback...&lt;br /&gt;
&lt;br /&gt;
I am using a simple calculated question on 2,0 or a calculated question on 1,9  to test the various combinations with different answers and tolerances.&lt;br /&gt;
&lt;br /&gt;
The range (Min- Max ) is available directly.&lt;br /&gt;
&lt;br /&gt;
At first tests your proposal seems to be working.&lt;br /&gt;
&lt;br /&gt;
I will report here the results of various tests on 1,9, actual 2, your proposal and the more linear code.&lt;br /&gt;
&lt;br /&gt;
This should help us to choose which tests to use.&lt;br /&gt;
&lt;br /&gt;
[[User:Pierre Pichet|Pierre Pichet]] 12:38, 16 August 2012 (WST)&lt;br /&gt;
=Tests results=&lt;br /&gt;
Types&lt;br /&gt;
* R :relative &lt;br /&gt;
*N  :nominal &lt;br /&gt;
*G  : geometric&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Answer!!Tolerance !!Type    !! 1,9 Min!! 1,9 Max!! Code Min !! Code Max!! 2,0 Min!! 2,0 Max!! Tim Min!! Tim Max&lt;br /&gt;
|-&lt;br /&gt;
|0          ||  0          ||  N      ||  0        ||  0    ||  -1.0E-14 ||  1.0E-14||  -1.0E-14  ||  1.0E-14  || -1.0E-28    ||  1.0E-28      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  1e-24    ||  N    || 0   || 0    ||  -1.0E-24 ||  1.0E-24||  -1.0000000001E-14   ||  +1.0000000001E-14   ||  -1.0001E-24    ||  1.0001E-24     &lt;br /&gt;
|-&lt;br /&gt;
|1e-20          ||  0   ||  N|| 9.9999999999999E-21  ||  1.0E-20    ||  9.9999999999999E-21 ||  1.0E-20||  -9.99999E-15   ||  1.000001E-14   || 9.9999999999999E-21    ||  1.0E-20     &lt;br /&gt;
|-&lt;br /&gt;
|1e-20          ||  1e-24    || N || 9.999E-21   ||  1.0001E-20|| 9.999E-21||1.0001E-20 ||  -9.999990001E-15   ||  1.0000010001E-14   ||  9.9989999E-21    ||  1.00010001E-20      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The tests on master, Tim proposal and code proposal are done on the same installation just changing the branchs (master) created for the tests so everything else is constant.&lt;br /&gt;
&lt;br /&gt;
The Code proposal give similar results to the 1,9 version with a more precise handling of 0 as answer.&lt;br /&gt;
&lt;br /&gt;
TODO : Review the Code proposal , use as suggested $epsilon, ....&lt;br /&gt;
=Final Code proposal=&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If we add &lt;br /&gt;
&lt;br /&gt;
 $epsilon = pow(10, -1 * ini_get(&#039;precision&#039;));&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34893</id>
		<title>Question Engine 2:Numerical tolerances</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34893"/>
		<updated>2012-08-17T00:36:04Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: /* Tests results */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Analysis of the various tolerances for numerical and calculated question type answer see (MDL-31837)&lt;br /&gt;
&lt;br /&gt;
In grading a numerical response, the (student) numerical value is compared to the answer numerical value.&lt;br /&gt;
&lt;br /&gt;
This comparison allow a tolerance that is associated with the answer and that can be expressed in various ways.&lt;br /&gt;
&lt;br /&gt;
For calculated question answers the tolerance can be of 3 different types: relative, nominal or geometric. &lt;br /&gt;
=Limits of real numbers in PHP=&lt;br /&gt;
&lt;br /&gt;
The following is from http://www.php.net/manual/en/language.types.float.php&lt;br /&gt;
&lt;br /&gt;
The size of a float is platform-dependent, although a maximum of ~1.8e308 with a precision of roughly 14 decimal digits is a common value (the 64 bit IEEE format).&lt;br /&gt;
&lt;br /&gt;
 Warning&lt;br /&gt;
 Floating point precision&lt;br /&gt;
&lt;br /&gt;
Floating point numbers have limited precision. Although it depends on the system, PHP typically uses the IEEE 754 double precision format, which will give a maximum relative error due to rounding in the order of 1.11e-16. Non elementary arithmetic operations may give larger errors, and, of course, error propagation must be considered when several operations are compounded.&lt;br /&gt;
&lt;br /&gt;
Additionally, rational numbers that are exactly representable as floating point numbers in base 10, like 0.1 or 0.7, do not have an exact representation as floating point numbers in base 2, which is used internally, no matter the size of the mantissa. Hence, they cannot be converted into their internal binary counterparts without a small loss of precision. This can lead to confusing results: for example, floor((0.1+0.7)*10) will usually return 7 instead of the expected 8, since the internal representation will be something like 7.9999999999999991118....&lt;br /&gt;
&lt;br /&gt;
So never trust floating number results to the last digit, and do not compare floating point numbers directly for equality. If higher precision is necessary, the arbitrary precision math functions and gmp functions are available.&lt;br /&gt;
&lt;br /&gt;
Since the internal representation is in base 2, 0 and 1 will have the same exponent so the precision ( i.e. init_get(&#039;precision&#039;) should have the same value.?&lt;br /&gt;
&lt;br /&gt;
....&lt;br /&gt;
=1,9 version=&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
function get_tolerance_interval(&amp;amp;$answer) {&lt;br /&gt;
        // No tolerance&lt;br /&gt;
        if (empty($answer-&amp;gt;tolerance)) {&lt;br /&gt;
            $answer-&amp;gt;tolerance = 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Calculate the interval of correct responses (min/max)&lt;br /&gt;
        if (!isset($answer-&amp;gt;tolerancetype)) {&lt;br /&gt;
            $answer-&amp;gt;tolerancetype = 2; // nominal&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make the&lt;br /&gt;
        // comparison work correctly. Otherwise seemingly equal values can yield&lt;br /&gt;
        // false. (fixes bug #3225)&lt;br /&gt;
        $tolerance = (float)$answer-&amp;gt;tolerance + (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;));&lt;br /&gt;
        switch ($answer-&amp;gt;tolerancetype) {&lt;br /&gt;
            case &#039;1&#039;: case &#039;relative&#039;:&lt;br /&gt;
                /// Recalculate the tolerance and fall through&lt;br /&gt;
                /// to the nominal case:&lt;br /&gt;
                $tolerance = $answer-&amp;gt;answer * $tolerance;&lt;br /&gt;
                // Do not fall through to the nominal case because the tiny fraction is a factor of the answer&lt;br /&gt;
                 $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;2&#039;: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                // $answer-&amp;gt;tolerance 0 or something else&lt;br /&gt;
                if ((float)$answer-&amp;gt;tolerance == 0.0  &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance ){&lt;br /&gt;
                    $tolerance = (float) (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) * abs((float)$answer-&amp;gt;answer) ; //tiny fraction&lt;br /&gt;
                } else if ((float)$answer-&amp;gt;tolerance != 0.0 &amp;amp;&amp;amp; abs((float)$answer-&amp;gt;tolerance) &amp;lt; abs((float)$answer-&amp;gt;answer) &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance){&lt;br /&gt;
                    $tolerance = (1+(&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) )* abs((float) $answer-&amp;gt;tolerance) ;//tiny fraction&lt;br /&gt;
               }&lt;br /&gt;
&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;3&#039;: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                $max = $answer-&amp;gt;answer * $quotient;&lt;br /&gt;
                $min = $answer-&amp;gt;answer / $quotient;&lt;br /&gt;
                break;&lt;br /&gt;
            default:&lt;br /&gt;
                error(&amp;quot;Unknown tolerance type $answer-&amp;gt;tolerancetype&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $answer-&amp;gt;min = $min;&lt;br /&gt;
        $answer-&amp;gt;max = $max;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 actual code=&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class qtype_numerical_answer extends question_answer {&lt;br /&gt;
    /** @var float allowable margin of error. */&lt;br /&gt;
    public $tolerance;&lt;br /&gt;
    /** @var integer|string see {@link get_tolerance_interval()} for the meaning of this value. */&lt;br /&gt;
    public $tolerancetype = 2;&lt;br /&gt;
&lt;br /&gt;
    public function __construct($id, $answer, $fraction, $feedback, $feedbackformat, $tolerance) {&lt;br /&gt;
        parent::__construct($id, $answer, $fraction, $feedback, $feedbackformat);&lt;br /&gt;
        $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_tolerance_interval() {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            throw new coding_exception(&#039;Cannot work out tolerance interval for answer *.&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make&lt;br /&gt;
        // the comparison work correctly, otherwise seemingly equal values can&lt;br /&gt;
        // yield false. See MDL-3225.&lt;br /&gt;
        $tolerance = (float) $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;));&lt;br /&gt;
&lt;br /&gt;
        switch ($this-&amp;gt;tolerancetype) {&lt;br /&gt;
            case 1: case &#039;relative&#039;:&lt;br /&gt;
                $range = abs($this-&amp;gt;answer) * $tolerance;&lt;br /&gt;
                return array($this-&amp;gt;answer - $range, $this-&amp;gt;answer + $range);&lt;br /&gt;
&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) *&lt;br /&gt;
                        max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&lt;br /&gt;
            case 3: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                return array($this-&amp;gt;answer / $quotient, $this-&amp;gt;answer * $quotient);&lt;br /&gt;
&lt;br /&gt;
            default:&lt;br /&gt;
                throw new coding_exception(&#039;Unknown tolerance type &#039; . $this-&amp;gt;tolerancetype);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function within_tolerance($value) {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
        list($min, $max) = $this-&amp;gt;get_tolerance_interval();&lt;br /&gt;
        return $min &amp;lt;= $value &amp;amp;&amp;amp; $value &amp;lt;= $max;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 vs 1,9 differences=&lt;br /&gt;
== case relative ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case geometric ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case nominal ==&lt;br /&gt;
The use of &lt;br /&gt;
 pow(10, -1 * ini_get(&#039;precision&#039;)) * max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
The &#039;tiny fraction&#039; part of the tolerance  is not related to the answer when the answer is less than 1. &lt;br /&gt;
&lt;br /&gt;
We should get back to the 1,9 equivalent code first by removing the max function &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The 1,9 code has a special treatment of the answer == 0 .&lt;br /&gt;
&lt;br /&gt;
Should we keep the code ?&lt;br /&gt;
&lt;br /&gt;
=== Answer is 0===&lt;br /&gt;
What is the precision of 0 ?&lt;br /&gt;
It cannot be 0 , it only can be the precision of the digital part of the number i.e.  pow(10, -1 * ini_get(&#039;precision&#039;)).&lt;br /&gt;
As a mather of fact the exponent part of 0 is the same one as 1 so its precision is the same.&lt;br /&gt;
We should not forget that the &amp;quot;turning point&amp;quot; (positive to negative)  of real number exponent value is 1 not 0.&lt;br /&gt;
&lt;br /&gt;
So to get the &amp;quot;tiny number&amp;quot; we should multiply the  pow(10, -1 * ini_get(&#039;precision&#039;)) by $this-&amp;gt;answer except when $this-&amp;gt;answer == 0 when it should be 1.&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 0,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;pow(10, -1 * ini_get(&#039;precision&#039;))=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
&lt;br /&gt;
=== Answer is NOT 0===&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;tiny part&amp;quot; should mostly be calculated as pow(10, -1 * ini_get(&#039;precision&#039;))*$answer&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 2,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;=pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))** $this-&amp;gt;answer ;&lt;br /&gt;
&lt;br /&gt;
=Code flow proposal=&lt;br /&gt;
&lt;br /&gt;
This code reflects the discussion although a more concise version could be built.&lt;br /&gt;
The proposal is somehow different from the 1,9 version as it includes the precision of the tolerance in the range.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    if ($this-&amp;gt;answer == 0.0){&lt;br /&gt;
         if($this-&amp;gt;tolerance == 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)){ // the 0&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         }&lt;br /&gt;
   } else {&lt;br /&gt;
         if($this-&amp;gt;tolerance === 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;answer ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)* abs($this-&amp;gt;answer)){ &lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
         }     &lt;br /&gt;
   }         &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Tim&#039;s idea==&lt;br /&gt;
&lt;br /&gt;
I am wondering whether it works just change &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the 2.0 code to&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max($this-&amp;gt;tolerance, abs($this-&amp;gt;answer), pow(10, -1 * ini_get(&#039;precision&#039;)));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code might be nicer if we define $epsilon = pow(10, -1 * ini_get(&#039;precision&#039;)) at the start of the function.&lt;br /&gt;
&lt;br /&gt;
Finally, I would like to know what tests you propose to add to question/type/numerical/tests/answer_test.php in order to demonstrate that everything is working properly. In particular, what tests would you like to add that will fail with the current code, but which will pass once we have fixed this bug?&lt;br /&gt;
&lt;br /&gt;
--[[User:Tim Hunt|Tim Hunt]] 00:53, 16 August 2012 (WST)&lt;br /&gt;
==Pierre&#039;s comment==&lt;br /&gt;
Thanks for your code expert feedback...&lt;br /&gt;
&lt;br /&gt;
I am using a simple calculated question on 2,0 or a calculated question on 1,9  to test the various combinations with different answers and tolerances.&lt;br /&gt;
&lt;br /&gt;
The range (Min- Max ) is available directly.&lt;br /&gt;
&lt;br /&gt;
At first tests your proposal seems to be working.&lt;br /&gt;
&lt;br /&gt;
I will report here the results of various tests on 1,9, actual 2, your proposal and the more linear code.&lt;br /&gt;
&lt;br /&gt;
This should help us to choose which tests to use.&lt;br /&gt;
&lt;br /&gt;
[[User:Pierre Pichet|Pierre Pichet]] 12:38, 16 August 2012 (WST)&lt;br /&gt;
=Tests results=&lt;br /&gt;
Types&lt;br /&gt;
* R :relative &lt;br /&gt;
*N  :nominal &lt;br /&gt;
*G  : geometric&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Answer!!Tolerance !!Type    !! 1,9 Min!! 1,9 Max!! Code Min !! Code Max!! 2,0 Min!! 2,0 Max!! Tim Min!! Tim Max&lt;br /&gt;
|-&lt;br /&gt;
|0          ||  0          ||  N      ||  0        ||  0    ||  -1.0E-14 ||  1.0E-14||  -1.0E-14  ||  1.0E-14  || -1.0E-28    ||  1.0E-28      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  1e-24    ||  N    || 0   || 0    ||  -1.0E-24 ||  1.0E-24||  -1.0000000001E-14   ||  +1.0000000001E-14   ||  -1.0001E-24    ||  1.0001E-24     &lt;br /&gt;
|-&lt;br /&gt;
|1e-20          ||  0   ||  N|| 9.9999999999999E-21  ||  1.0E-20    ||  9.9999999999999E-21 ||  1.0E-20||  -9.99999E-15   ||  1.000001E-14   || 9.9999999999999E-21    ||  1.0E-20     &lt;br /&gt;
|-&lt;br /&gt;
|1e-20          ||  1e-24    || N || 9.999E-21   ||  1.0001E-20|| 9.999E-21||1.0001E-20 ||  -9.999990001E-15   ||  1.0000010001E-14   ||  9.9989999E-21    ||  1.00010001E-20      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The tests on master, Tim proposal and code proposal are done on the same installation just changing the branchs (master) created for the tests so everything else is constant.&lt;br /&gt;
&lt;br /&gt;
The Code proposal give similar results to the 1,9 version with a more precise handling of 0 as answer.&lt;br /&gt;
&lt;br /&gt;
TODO : Review the Code proposal , use as suggested $epsilon, ....&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34891</id>
		<title>Question Engine 2:Numerical tolerances</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34891"/>
		<updated>2012-08-17T00:20:37Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: /* Tests results */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Analysis of the various tolerances for numerical and calculated question type answer see (MDL-31837)&lt;br /&gt;
&lt;br /&gt;
In grading a numerical response, the (student) numerical value is compared to the answer numerical value.&lt;br /&gt;
&lt;br /&gt;
This comparison allow a tolerance that is associated with the answer and that can be expressed in various ways.&lt;br /&gt;
&lt;br /&gt;
For calculated question answers the tolerance can be of 3 different types: relative, nominal or geometric. &lt;br /&gt;
=Limits of real numbers in PHP=&lt;br /&gt;
&lt;br /&gt;
The following is from http://www.php.net/manual/en/language.types.float.php&lt;br /&gt;
&lt;br /&gt;
The size of a float is platform-dependent, although a maximum of ~1.8e308 with a precision of roughly 14 decimal digits is a common value (the 64 bit IEEE format).&lt;br /&gt;
&lt;br /&gt;
 Warning&lt;br /&gt;
 Floating point precision&lt;br /&gt;
&lt;br /&gt;
Floating point numbers have limited precision. Although it depends on the system, PHP typically uses the IEEE 754 double precision format, which will give a maximum relative error due to rounding in the order of 1.11e-16. Non elementary arithmetic operations may give larger errors, and, of course, error propagation must be considered when several operations are compounded.&lt;br /&gt;
&lt;br /&gt;
Additionally, rational numbers that are exactly representable as floating point numbers in base 10, like 0.1 or 0.7, do not have an exact representation as floating point numbers in base 2, which is used internally, no matter the size of the mantissa. Hence, they cannot be converted into their internal binary counterparts without a small loss of precision. This can lead to confusing results: for example, floor((0.1+0.7)*10) will usually return 7 instead of the expected 8, since the internal representation will be something like 7.9999999999999991118....&lt;br /&gt;
&lt;br /&gt;
So never trust floating number results to the last digit, and do not compare floating point numbers directly for equality. If higher precision is necessary, the arbitrary precision math functions and gmp functions are available.&lt;br /&gt;
&lt;br /&gt;
Since the internal representation is in base 2, 0 and 1 will have the same exponent so the precision ( i.e. init_get(&#039;precision&#039;) should have the same value.?&lt;br /&gt;
&lt;br /&gt;
....&lt;br /&gt;
=1,9 version=&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
function get_tolerance_interval(&amp;amp;$answer) {&lt;br /&gt;
        // No tolerance&lt;br /&gt;
        if (empty($answer-&amp;gt;tolerance)) {&lt;br /&gt;
            $answer-&amp;gt;tolerance = 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Calculate the interval of correct responses (min/max)&lt;br /&gt;
        if (!isset($answer-&amp;gt;tolerancetype)) {&lt;br /&gt;
            $answer-&amp;gt;tolerancetype = 2; // nominal&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make the&lt;br /&gt;
        // comparison work correctly. Otherwise seemingly equal values can yield&lt;br /&gt;
        // false. (fixes bug #3225)&lt;br /&gt;
        $tolerance = (float)$answer-&amp;gt;tolerance + (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;));&lt;br /&gt;
        switch ($answer-&amp;gt;tolerancetype) {&lt;br /&gt;
            case &#039;1&#039;: case &#039;relative&#039;:&lt;br /&gt;
                /// Recalculate the tolerance and fall through&lt;br /&gt;
                /// to the nominal case:&lt;br /&gt;
                $tolerance = $answer-&amp;gt;answer * $tolerance;&lt;br /&gt;
                // Do not fall through to the nominal case because the tiny fraction is a factor of the answer&lt;br /&gt;
                 $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;2&#039;: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                // $answer-&amp;gt;tolerance 0 or something else&lt;br /&gt;
                if ((float)$answer-&amp;gt;tolerance == 0.0  &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance ){&lt;br /&gt;
                    $tolerance = (float) (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) * abs((float)$answer-&amp;gt;answer) ; //tiny fraction&lt;br /&gt;
                } else if ((float)$answer-&amp;gt;tolerance != 0.0 &amp;amp;&amp;amp; abs((float)$answer-&amp;gt;tolerance) &amp;lt; abs((float)$answer-&amp;gt;answer) &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance){&lt;br /&gt;
                    $tolerance = (1+(&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) )* abs((float) $answer-&amp;gt;tolerance) ;//tiny fraction&lt;br /&gt;
               }&lt;br /&gt;
&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;3&#039;: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                $max = $answer-&amp;gt;answer * $quotient;&lt;br /&gt;
                $min = $answer-&amp;gt;answer / $quotient;&lt;br /&gt;
                break;&lt;br /&gt;
            default:&lt;br /&gt;
                error(&amp;quot;Unknown tolerance type $answer-&amp;gt;tolerancetype&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $answer-&amp;gt;min = $min;&lt;br /&gt;
        $answer-&amp;gt;max = $max;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 actual code=&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class qtype_numerical_answer extends question_answer {&lt;br /&gt;
    /** @var float allowable margin of error. */&lt;br /&gt;
    public $tolerance;&lt;br /&gt;
    /** @var integer|string see {@link get_tolerance_interval()} for the meaning of this value. */&lt;br /&gt;
    public $tolerancetype = 2;&lt;br /&gt;
&lt;br /&gt;
    public function __construct($id, $answer, $fraction, $feedback, $feedbackformat, $tolerance) {&lt;br /&gt;
        parent::__construct($id, $answer, $fraction, $feedback, $feedbackformat);&lt;br /&gt;
        $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_tolerance_interval() {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            throw new coding_exception(&#039;Cannot work out tolerance interval for answer *.&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make&lt;br /&gt;
        // the comparison work correctly, otherwise seemingly equal values can&lt;br /&gt;
        // yield false. See MDL-3225.&lt;br /&gt;
        $tolerance = (float) $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;));&lt;br /&gt;
&lt;br /&gt;
        switch ($this-&amp;gt;tolerancetype) {&lt;br /&gt;
            case 1: case &#039;relative&#039;:&lt;br /&gt;
                $range = abs($this-&amp;gt;answer) * $tolerance;&lt;br /&gt;
                return array($this-&amp;gt;answer - $range, $this-&amp;gt;answer + $range);&lt;br /&gt;
&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) *&lt;br /&gt;
                        max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&lt;br /&gt;
            case 3: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                return array($this-&amp;gt;answer / $quotient, $this-&amp;gt;answer * $quotient);&lt;br /&gt;
&lt;br /&gt;
            default:&lt;br /&gt;
                throw new coding_exception(&#039;Unknown tolerance type &#039; . $this-&amp;gt;tolerancetype);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function within_tolerance($value) {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
        list($min, $max) = $this-&amp;gt;get_tolerance_interval();&lt;br /&gt;
        return $min &amp;lt;= $value &amp;amp;&amp;amp; $value &amp;lt;= $max;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 vs 1,9 differences=&lt;br /&gt;
== case relative ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case geometric ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case nominal ==&lt;br /&gt;
The use of &lt;br /&gt;
 pow(10, -1 * ini_get(&#039;precision&#039;)) * max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
The &#039;tiny fraction&#039; part of the tolerance  is not related to the answer when the answer is less than 1. &lt;br /&gt;
&lt;br /&gt;
We should get back to the 1,9 equivalent code first by removing the max function &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The 1,9 code has a special treatment of the answer == 0 .&lt;br /&gt;
&lt;br /&gt;
Should we keep the code ?&lt;br /&gt;
&lt;br /&gt;
=== Answer is 0===&lt;br /&gt;
What is the precision of 0 ?&lt;br /&gt;
It cannot be 0 , it only can be the precision of the digital part of the number i.e.  pow(10, -1 * ini_get(&#039;precision&#039;)).&lt;br /&gt;
As a mather of fact the exponent part of 0 is the same one as 1 so its precision is the same.&lt;br /&gt;
We should not forget that the &amp;quot;turning point&amp;quot; (positive to negative)  of real number exponent value is 1 not 0.&lt;br /&gt;
&lt;br /&gt;
So to get the &amp;quot;tiny number&amp;quot; we should multiply the  pow(10, -1 * ini_get(&#039;precision&#039;)) by $this-&amp;gt;answer except when $this-&amp;gt;answer == 0 when it should be 1.&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 0,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;pow(10, -1 * ini_get(&#039;precision&#039;))=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
&lt;br /&gt;
=== Answer is NOT 0===&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;tiny part&amp;quot; should mostly be calculated as pow(10, -1 * ini_get(&#039;precision&#039;))*$answer&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 2,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;=pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))** $this-&amp;gt;answer ;&lt;br /&gt;
&lt;br /&gt;
=Code flow proposal=&lt;br /&gt;
&lt;br /&gt;
This code reflects the discussion although a more concise version could be built.&lt;br /&gt;
The proposal is somehow different from the 1,9 version as it includes the precision of the tolerance in the range.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    if ($this-&amp;gt;answer == 0.0){&lt;br /&gt;
         if($this-&amp;gt;tolerance == 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)){ // the 0&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         }&lt;br /&gt;
   } else {&lt;br /&gt;
         if($this-&amp;gt;tolerance === 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;answer ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)* abs($this-&amp;gt;answer)){ &lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
         }     &lt;br /&gt;
   }         &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Tim&#039;s idea==&lt;br /&gt;
&lt;br /&gt;
I am wondering whether it works just change &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the 2.0 code to&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max($this-&amp;gt;tolerance, abs($this-&amp;gt;answer), pow(10, -1 * ini_get(&#039;precision&#039;)));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code might be nicer if we define $epsilon = pow(10, -1 * ini_get(&#039;precision&#039;)) at the start of the function.&lt;br /&gt;
&lt;br /&gt;
Finally, I would like to know what tests you propose to add to question/type/numerical/tests/answer_test.php in order to demonstrate that everything is working properly. In particular, what tests would you like to add that will fail with the current code, but which will pass once we have fixed this bug?&lt;br /&gt;
&lt;br /&gt;
--[[User:Tim Hunt|Tim Hunt]] 00:53, 16 August 2012 (WST)&lt;br /&gt;
==Pierre&#039;s comment==&lt;br /&gt;
Thanks for your code expert feedback...&lt;br /&gt;
&lt;br /&gt;
I am using a simple calculated question on 2,0 or a calculated question on 1,9  to test the various combinations with different answers and tolerances.&lt;br /&gt;
&lt;br /&gt;
The range (Min- Max ) is available directly.&lt;br /&gt;
&lt;br /&gt;
At first tests your proposal seems to be working.&lt;br /&gt;
&lt;br /&gt;
I will report here the results of various tests on 1,9, actual 2, your proposal and the more linear code.&lt;br /&gt;
&lt;br /&gt;
This should help us to choose which tests to use.&lt;br /&gt;
&lt;br /&gt;
[[User:Pierre Pichet|Pierre Pichet]] 12:38, 16 August 2012 (WST)&lt;br /&gt;
=Tests results=&lt;br /&gt;
Types&lt;br /&gt;
* R :relative &lt;br /&gt;
*N  :nominal &lt;br /&gt;
*G  : geometric&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Answer!!Tolerance !!Type    !! 1,9 Min!! 1,9 Max!! Code Min !! Code Max!! 2,0 Min!! 2,0 Max!! Tim Min!! Tim Max&lt;br /&gt;
|-&lt;br /&gt;
|0          ||  0          ||  N      ||  0        ||  0    ||  -1.0E-14 ||  1.0E-14||  -1.0E-14  ||  1.0E-14  || -1.0E-28    ||  1.0E-28      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  1e-24    ||  N    || 0   || 0    ||  -1.0E-24 ||  1.0E-24||  -1.0000000001E-14   ||  +1.0000000001E-14   ||  -1.0001E-24    ||  1.0001E-24     &lt;br /&gt;
|-&lt;br /&gt;
|1e-20          ||  0   ||  N|| 9.9999999999999E-21  ||  1.0E-20    ||  9.9999999999999E-21 ||  1.0E-20||  -9.99999E-15   ||  1.000001E-14   || 9.9999999999999E-21    ||  1.0E-20     &lt;br /&gt;
|-&lt;br /&gt;
|1e-20          ||  1e-24    || N || 9.999E-21   ||  1.0001E-20|| 9.999E-21||1.0001E-20 ||  -9.999990001E-15   ||  1.0000010001E-14   ||  9.9989999E-21    ||  1.00010001E-20      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The tests on master, Tim proposal and code proposal are done on the same installation just changing the branchs (master) created for the tests so everything else is constant.&lt;br /&gt;
&lt;br /&gt;
The Code proposal give similar results to the 1,9 version with a more precise handling of 0 as answer.&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34890</id>
		<title>Question Engine 2:Numerical tolerances</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34890"/>
		<updated>2012-08-17T00:12:51Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: /* Tests results */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Analysis of the various tolerances for numerical and calculated question type answer see (MDL-31837)&lt;br /&gt;
&lt;br /&gt;
In grading a numerical response, the (student) numerical value is compared to the answer numerical value.&lt;br /&gt;
&lt;br /&gt;
This comparison allow a tolerance that is associated with the answer and that can be expressed in various ways.&lt;br /&gt;
&lt;br /&gt;
For calculated question answers the tolerance can be of 3 different types: relative, nominal or geometric. &lt;br /&gt;
=Limits of real numbers in PHP=&lt;br /&gt;
&lt;br /&gt;
The following is from http://www.php.net/manual/en/language.types.float.php&lt;br /&gt;
&lt;br /&gt;
The size of a float is platform-dependent, although a maximum of ~1.8e308 with a precision of roughly 14 decimal digits is a common value (the 64 bit IEEE format).&lt;br /&gt;
&lt;br /&gt;
 Warning&lt;br /&gt;
 Floating point precision&lt;br /&gt;
&lt;br /&gt;
Floating point numbers have limited precision. Although it depends on the system, PHP typically uses the IEEE 754 double precision format, which will give a maximum relative error due to rounding in the order of 1.11e-16. Non elementary arithmetic operations may give larger errors, and, of course, error propagation must be considered when several operations are compounded.&lt;br /&gt;
&lt;br /&gt;
Additionally, rational numbers that are exactly representable as floating point numbers in base 10, like 0.1 or 0.7, do not have an exact representation as floating point numbers in base 2, which is used internally, no matter the size of the mantissa. Hence, they cannot be converted into their internal binary counterparts without a small loss of precision. This can lead to confusing results: for example, floor((0.1+0.7)*10) will usually return 7 instead of the expected 8, since the internal representation will be something like 7.9999999999999991118....&lt;br /&gt;
&lt;br /&gt;
So never trust floating number results to the last digit, and do not compare floating point numbers directly for equality. If higher precision is necessary, the arbitrary precision math functions and gmp functions are available.&lt;br /&gt;
&lt;br /&gt;
Since the internal representation is in base 2, 0 and 1 will have the same exponent so the precision ( i.e. init_get(&#039;precision&#039;) should have the same value.?&lt;br /&gt;
&lt;br /&gt;
....&lt;br /&gt;
=1,9 version=&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
function get_tolerance_interval(&amp;amp;$answer) {&lt;br /&gt;
        // No tolerance&lt;br /&gt;
        if (empty($answer-&amp;gt;tolerance)) {&lt;br /&gt;
            $answer-&amp;gt;tolerance = 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Calculate the interval of correct responses (min/max)&lt;br /&gt;
        if (!isset($answer-&amp;gt;tolerancetype)) {&lt;br /&gt;
            $answer-&amp;gt;tolerancetype = 2; // nominal&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make the&lt;br /&gt;
        // comparison work correctly. Otherwise seemingly equal values can yield&lt;br /&gt;
        // false. (fixes bug #3225)&lt;br /&gt;
        $tolerance = (float)$answer-&amp;gt;tolerance + (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;));&lt;br /&gt;
        switch ($answer-&amp;gt;tolerancetype) {&lt;br /&gt;
            case &#039;1&#039;: case &#039;relative&#039;:&lt;br /&gt;
                /// Recalculate the tolerance and fall through&lt;br /&gt;
                /// to the nominal case:&lt;br /&gt;
                $tolerance = $answer-&amp;gt;answer * $tolerance;&lt;br /&gt;
                // Do not fall through to the nominal case because the tiny fraction is a factor of the answer&lt;br /&gt;
                 $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;2&#039;: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                // $answer-&amp;gt;tolerance 0 or something else&lt;br /&gt;
                if ((float)$answer-&amp;gt;tolerance == 0.0  &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance ){&lt;br /&gt;
                    $tolerance = (float) (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) * abs((float)$answer-&amp;gt;answer) ; //tiny fraction&lt;br /&gt;
                } else if ((float)$answer-&amp;gt;tolerance != 0.0 &amp;amp;&amp;amp; abs((float)$answer-&amp;gt;tolerance) &amp;lt; abs((float)$answer-&amp;gt;answer) &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance){&lt;br /&gt;
                    $tolerance = (1+(&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) )* abs((float) $answer-&amp;gt;tolerance) ;//tiny fraction&lt;br /&gt;
               }&lt;br /&gt;
&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;3&#039;: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                $max = $answer-&amp;gt;answer * $quotient;&lt;br /&gt;
                $min = $answer-&amp;gt;answer / $quotient;&lt;br /&gt;
                break;&lt;br /&gt;
            default:&lt;br /&gt;
                error(&amp;quot;Unknown tolerance type $answer-&amp;gt;tolerancetype&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $answer-&amp;gt;min = $min;&lt;br /&gt;
        $answer-&amp;gt;max = $max;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 actual code=&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class qtype_numerical_answer extends question_answer {&lt;br /&gt;
    /** @var float allowable margin of error. */&lt;br /&gt;
    public $tolerance;&lt;br /&gt;
    /** @var integer|string see {@link get_tolerance_interval()} for the meaning of this value. */&lt;br /&gt;
    public $tolerancetype = 2;&lt;br /&gt;
&lt;br /&gt;
    public function __construct($id, $answer, $fraction, $feedback, $feedbackformat, $tolerance) {&lt;br /&gt;
        parent::__construct($id, $answer, $fraction, $feedback, $feedbackformat);&lt;br /&gt;
        $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_tolerance_interval() {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            throw new coding_exception(&#039;Cannot work out tolerance interval for answer *.&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make&lt;br /&gt;
        // the comparison work correctly, otherwise seemingly equal values can&lt;br /&gt;
        // yield false. See MDL-3225.&lt;br /&gt;
        $tolerance = (float) $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;));&lt;br /&gt;
&lt;br /&gt;
        switch ($this-&amp;gt;tolerancetype) {&lt;br /&gt;
            case 1: case &#039;relative&#039;:&lt;br /&gt;
                $range = abs($this-&amp;gt;answer) * $tolerance;&lt;br /&gt;
                return array($this-&amp;gt;answer - $range, $this-&amp;gt;answer + $range);&lt;br /&gt;
&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) *&lt;br /&gt;
                        max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&lt;br /&gt;
            case 3: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                return array($this-&amp;gt;answer / $quotient, $this-&amp;gt;answer * $quotient);&lt;br /&gt;
&lt;br /&gt;
            default:&lt;br /&gt;
                throw new coding_exception(&#039;Unknown tolerance type &#039; . $this-&amp;gt;tolerancetype);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function within_tolerance($value) {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
        list($min, $max) = $this-&amp;gt;get_tolerance_interval();&lt;br /&gt;
        return $min &amp;lt;= $value &amp;amp;&amp;amp; $value &amp;lt;= $max;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 vs 1,9 differences=&lt;br /&gt;
== case relative ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case geometric ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case nominal ==&lt;br /&gt;
The use of &lt;br /&gt;
 pow(10, -1 * ini_get(&#039;precision&#039;)) * max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
The &#039;tiny fraction&#039; part of the tolerance  is not related to the answer when the answer is less than 1. &lt;br /&gt;
&lt;br /&gt;
We should get back to the 1,9 equivalent code first by removing the max function &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The 1,9 code has a special treatment of the answer == 0 .&lt;br /&gt;
&lt;br /&gt;
Should we keep the code ?&lt;br /&gt;
&lt;br /&gt;
=== Answer is 0===&lt;br /&gt;
What is the precision of 0 ?&lt;br /&gt;
It cannot be 0 , it only can be the precision of the digital part of the number i.e.  pow(10, -1 * ini_get(&#039;precision&#039;)).&lt;br /&gt;
As a mather of fact the exponent part of 0 is the same one as 1 so its precision is the same.&lt;br /&gt;
We should not forget that the &amp;quot;turning point&amp;quot; (positive to negative)  of real number exponent value is 1 not 0.&lt;br /&gt;
&lt;br /&gt;
So to get the &amp;quot;tiny number&amp;quot; we should multiply the  pow(10, -1 * ini_get(&#039;precision&#039;)) by $this-&amp;gt;answer except when $this-&amp;gt;answer == 0 when it should be 1.&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 0,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;pow(10, -1 * ini_get(&#039;precision&#039;))=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
&lt;br /&gt;
=== Answer is NOT 0===&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;tiny part&amp;quot; should mostly be calculated as pow(10, -1 * ini_get(&#039;precision&#039;))*$answer&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 2,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;=pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))** $this-&amp;gt;answer ;&lt;br /&gt;
&lt;br /&gt;
=Code flow proposal=&lt;br /&gt;
&lt;br /&gt;
This code reflects the discussion although a more concise version could be built.&lt;br /&gt;
The proposal is somehow different from the 1,9 version as it includes the precision of the tolerance in the range.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    if ($this-&amp;gt;answer == 0.0){&lt;br /&gt;
         if($this-&amp;gt;tolerance == 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)){ // the 0&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         }&lt;br /&gt;
   } else {&lt;br /&gt;
         if($this-&amp;gt;tolerance === 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;answer ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)* abs($this-&amp;gt;answer)){ &lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
         }     &lt;br /&gt;
   }         &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Tim&#039;s idea==&lt;br /&gt;
&lt;br /&gt;
I am wondering whether it works just change &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the 2.0 code to&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max($this-&amp;gt;tolerance, abs($this-&amp;gt;answer), pow(10, -1 * ini_get(&#039;precision&#039;)));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code might be nicer if we define $epsilon = pow(10, -1 * ini_get(&#039;precision&#039;)) at the start of the function.&lt;br /&gt;
&lt;br /&gt;
Finally, I would like to know what tests you propose to add to question/type/numerical/tests/answer_test.php in order to demonstrate that everything is working properly. In particular, what tests would you like to add that will fail with the current code, but which will pass once we have fixed this bug?&lt;br /&gt;
&lt;br /&gt;
--[[User:Tim Hunt|Tim Hunt]] 00:53, 16 August 2012 (WST)&lt;br /&gt;
==Pierre&#039;s comment==&lt;br /&gt;
Thanks for your code expert feedback...&lt;br /&gt;
&lt;br /&gt;
I am using a simple calculated question on 2,0 or a calculated question on 1,9  to test the various combinations with different answers and tolerances.&lt;br /&gt;
&lt;br /&gt;
The range (Min- Max ) is available directly.&lt;br /&gt;
&lt;br /&gt;
At first tests your proposal seems to be working.&lt;br /&gt;
&lt;br /&gt;
I will report here the results of various tests on 1,9, actual 2, your proposal and the more linear code.&lt;br /&gt;
&lt;br /&gt;
This should help us to choose which tests to use.&lt;br /&gt;
&lt;br /&gt;
[[User:Pierre Pichet|Pierre Pichet]] 12:38, 16 August 2012 (WST)&lt;br /&gt;
=Tests results=&lt;br /&gt;
Types&lt;br /&gt;
* R :relative &lt;br /&gt;
*N  :nominal &lt;br /&gt;
*G  : geometric&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Answer!!Tolerance !!Type    !! 1,9 Min!! 1,9 Max!! 2,0 Min!! 2,0 Max!! Tim Min!! Tim Max!! Code Min !! Code Max&lt;br /&gt;
|-&lt;br /&gt;
|0          ||  0          ||  N      ||  0        ||  0    ||  -1.0E-14  ||  1.0E-14  || -1.0E-28    ||  1.0E-28 ||  -1.0E-14 ||  1.0E-14      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  1e-24    ||  N    || 0   || 0    ||  -1.0000000001E-14   ||  +1.0000000001E-14   ||  -1.0001E-24    ||  1.0001E-24 ||  -1.0E-24 ||  1.0E-24     &lt;br /&gt;
|-&lt;br /&gt;
|1e-20          ||  0   ||  N|| 9.9999999999999E-21  ||  1.0E-20    ||  -9.99999E-15   ||  1.000001E-14   || 9.9999999999999E-21    ||  1.0E-20 ||  9.9999999999999E-21 ||  1.0E-20     &lt;br /&gt;
|-&lt;br /&gt;
|1e-20          ||  1e-24    || N || 9.999E-21||    1.0001E-20 ||  -9.999990001E-15   ||  1.0000010001E-14   ||  9.9989999E-21    ||  1.00010001E-20 || 9.999E-21 ||  1.0001E-20      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
The first tests show that Tim proposal does not calculate the 0 answer, 0 Tolerance to the correct value which should be the real number precision here 1*10-14&lt;br /&gt;
The tests on master, Tim proposal and code proposal are done on the same installation just changing the branchs (master) created for the tests so everything else is constant.&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34889</id>
		<title>Question Engine 2:Numerical tolerances</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34889"/>
		<updated>2012-08-16T23:51:14Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: /* Tests results */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Analysis of the various tolerances for numerical and calculated question type answer see (MDL-31837)&lt;br /&gt;
&lt;br /&gt;
In grading a numerical response, the (student) numerical value is compared to the answer numerical value.&lt;br /&gt;
&lt;br /&gt;
This comparison allow a tolerance that is associated with the answer and that can be expressed in various ways.&lt;br /&gt;
&lt;br /&gt;
For calculated question answers the tolerance can be of 3 different types: relative, nominal or geometric. &lt;br /&gt;
=Limits of real numbers in PHP=&lt;br /&gt;
&lt;br /&gt;
The following is from http://www.php.net/manual/en/language.types.float.php&lt;br /&gt;
&lt;br /&gt;
The size of a float is platform-dependent, although a maximum of ~1.8e308 with a precision of roughly 14 decimal digits is a common value (the 64 bit IEEE format).&lt;br /&gt;
&lt;br /&gt;
 Warning&lt;br /&gt;
 Floating point precision&lt;br /&gt;
&lt;br /&gt;
Floating point numbers have limited precision. Although it depends on the system, PHP typically uses the IEEE 754 double precision format, which will give a maximum relative error due to rounding in the order of 1.11e-16. Non elementary arithmetic operations may give larger errors, and, of course, error propagation must be considered when several operations are compounded.&lt;br /&gt;
&lt;br /&gt;
Additionally, rational numbers that are exactly representable as floating point numbers in base 10, like 0.1 or 0.7, do not have an exact representation as floating point numbers in base 2, which is used internally, no matter the size of the mantissa. Hence, they cannot be converted into their internal binary counterparts without a small loss of precision. This can lead to confusing results: for example, floor((0.1+0.7)*10) will usually return 7 instead of the expected 8, since the internal representation will be something like 7.9999999999999991118....&lt;br /&gt;
&lt;br /&gt;
So never trust floating number results to the last digit, and do not compare floating point numbers directly for equality. If higher precision is necessary, the arbitrary precision math functions and gmp functions are available.&lt;br /&gt;
&lt;br /&gt;
Since the internal representation is in base 2, 0 and 1 will have the same exponent so the precision ( i.e. init_get(&#039;precision&#039;) should have the same value.?&lt;br /&gt;
&lt;br /&gt;
....&lt;br /&gt;
=1,9 version=&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
function get_tolerance_interval(&amp;amp;$answer) {&lt;br /&gt;
        // No tolerance&lt;br /&gt;
        if (empty($answer-&amp;gt;tolerance)) {&lt;br /&gt;
            $answer-&amp;gt;tolerance = 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Calculate the interval of correct responses (min/max)&lt;br /&gt;
        if (!isset($answer-&amp;gt;tolerancetype)) {&lt;br /&gt;
            $answer-&amp;gt;tolerancetype = 2; // nominal&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make the&lt;br /&gt;
        // comparison work correctly. Otherwise seemingly equal values can yield&lt;br /&gt;
        // false. (fixes bug #3225)&lt;br /&gt;
        $tolerance = (float)$answer-&amp;gt;tolerance + (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;));&lt;br /&gt;
        switch ($answer-&amp;gt;tolerancetype) {&lt;br /&gt;
            case &#039;1&#039;: case &#039;relative&#039;:&lt;br /&gt;
                /// Recalculate the tolerance and fall through&lt;br /&gt;
                /// to the nominal case:&lt;br /&gt;
                $tolerance = $answer-&amp;gt;answer * $tolerance;&lt;br /&gt;
                // Do not fall through to the nominal case because the tiny fraction is a factor of the answer&lt;br /&gt;
                 $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;2&#039;: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                // $answer-&amp;gt;tolerance 0 or something else&lt;br /&gt;
                if ((float)$answer-&amp;gt;tolerance == 0.0  &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance ){&lt;br /&gt;
                    $tolerance = (float) (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) * abs((float)$answer-&amp;gt;answer) ; //tiny fraction&lt;br /&gt;
                } else if ((float)$answer-&amp;gt;tolerance != 0.0 &amp;amp;&amp;amp; abs((float)$answer-&amp;gt;tolerance) &amp;lt; abs((float)$answer-&amp;gt;answer) &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance){&lt;br /&gt;
                    $tolerance = (1+(&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) )* abs((float) $answer-&amp;gt;tolerance) ;//tiny fraction&lt;br /&gt;
               }&lt;br /&gt;
&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;3&#039;: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                $max = $answer-&amp;gt;answer * $quotient;&lt;br /&gt;
                $min = $answer-&amp;gt;answer / $quotient;&lt;br /&gt;
                break;&lt;br /&gt;
            default:&lt;br /&gt;
                error(&amp;quot;Unknown tolerance type $answer-&amp;gt;tolerancetype&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $answer-&amp;gt;min = $min;&lt;br /&gt;
        $answer-&amp;gt;max = $max;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 actual code=&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class qtype_numerical_answer extends question_answer {&lt;br /&gt;
    /** @var float allowable margin of error. */&lt;br /&gt;
    public $tolerance;&lt;br /&gt;
    /** @var integer|string see {@link get_tolerance_interval()} for the meaning of this value. */&lt;br /&gt;
    public $tolerancetype = 2;&lt;br /&gt;
&lt;br /&gt;
    public function __construct($id, $answer, $fraction, $feedback, $feedbackformat, $tolerance) {&lt;br /&gt;
        parent::__construct($id, $answer, $fraction, $feedback, $feedbackformat);&lt;br /&gt;
        $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_tolerance_interval() {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            throw new coding_exception(&#039;Cannot work out tolerance interval for answer *.&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make&lt;br /&gt;
        // the comparison work correctly, otherwise seemingly equal values can&lt;br /&gt;
        // yield false. See MDL-3225.&lt;br /&gt;
        $tolerance = (float) $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;));&lt;br /&gt;
&lt;br /&gt;
        switch ($this-&amp;gt;tolerancetype) {&lt;br /&gt;
            case 1: case &#039;relative&#039;:&lt;br /&gt;
                $range = abs($this-&amp;gt;answer) * $tolerance;&lt;br /&gt;
                return array($this-&amp;gt;answer - $range, $this-&amp;gt;answer + $range);&lt;br /&gt;
&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) *&lt;br /&gt;
                        max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&lt;br /&gt;
            case 3: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                return array($this-&amp;gt;answer / $quotient, $this-&amp;gt;answer * $quotient);&lt;br /&gt;
&lt;br /&gt;
            default:&lt;br /&gt;
                throw new coding_exception(&#039;Unknown tolerance type &#039; . $this-&amp;gt;tolerancetype);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function within_tolerance($value) {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
        list($min, $max) = $this-&amp;gt;get_tolerance_interval();&lt;br /&gt;
        return $min &amp;lt;= $value &amp;amp;&amp;amp; $value &amp;lt;= $max;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 vs 1,9 differences=&lt;br /&gt;
== case relative ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case geometric ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case nominal ==&lt;br /&gt;
The use of &lt;br /&gt;
 pow(10, -1 * ini_get(&#039;precision&#039;)) * max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
The &#039;tiny fraction&#039; part of the tolerance  is not related to the answer when the answer is less than 1. &lt;br /&gt;
&lt;br /&gt;
We should get back to the 1,9 equivalent code first by removing the max function &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The 1,9 code has a special treatment of the answer == 0 .&lt;br /&gt;
&lt;br /&gt;
Should we keep the code ?&lt;br /&gt;
&lt;br /&gt;
=== Answer is 0===&lt;br /&gt;
What is the precision of 0 ?&lt;br /&gt;
It cannot be 0 , it only can be the precision of the digital part of the number i.e.  pow(10, -1 * ini_get(&#039;precision&#039;)).&lt;br /&gt;
As a mather of fact the exponent part of 0 is the same one as 1 so its precision is the same.&lt;br /&gt;
We should not forget that the &amp;quot;turning point&amp;quot; (positive to negative)  of real number exponent value is 1 not 0.&lt;br /&gt;
&lt;br /&gt;
So to get the &amp;quot;tiny number&amp;quot; we should multiply the  pow(10, -1 * ini_get(&#039;precision&#039;)) by $this-&amp;gt;answer except when $this-&amp;gt;answer == 0 when it should be 1.&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 0,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;pow(10, -1 * ini_get(&#039;precision&#039;))=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
&lt;br /&gt;
=== Answer is NOT 0===&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;tiny part&amp;quot; should mostly be calculated as pow(10, -1 * ini_get(&#039;precision&#039;))*$answer&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 2,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;=pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))** $this-&amp;gt;answer ;&lt;br /&gt;
&lt;br /&gt;
=Code flow proposal=&lt;br /&gt;
&lt;br /&gt;
This code reflects the discussion although a more concise version could be built.&lt;br /&gt;
The proposal is somehow different from the 1,9 version as it includes the precision of the tolerance in the range.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    if ($this-&amp;gt;answer == 0.0){&lt;br /&gt;
         if($this-&amp;gt;tolerance == 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)){ // the 0&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         }&lt;br /&gt;
   } else {&lt;br /&gt;
         if($this-&amp;gt;tolerance === 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;answer ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)* abs($this-&amp;gt;answer)){ &lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
         }     &lt;br /&gt;
   }         &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Tim&#039;s idea==&lt;br /&gt;
&lt;br /&gt;
I am wondering whether it works just change &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the 2.0 code to&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max($this-&amp;gt;tolerance, abs($this-&amp;gt;answer), pow(10, -1 * ini_get(&#039;precision&#039;)));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code might be nicer if we define $epsilon = pow(10, -1 * ini_get(&#039;precision&#039;)) at the start of the function.&lt;br /&gt;
&lt;br /&gt;
Finally, I would like to know what tests you propose to add to question/type/numerical/tests/answer_test.php in order to demonstrate that everything is working properly. In particular, what tests would you like to add that will fail with the current code, but which will pass once we have fixed this bug?&lt;br /&gt;
&lt;br /&gt;
--[[User:Tim Hunt|Tim Hunt]] 00:53, 16 August 2012 (WST)&lt;br /&gt;
==Pierre&#039;s comment==&lt;br /&gt;
Thanks for your code expert feedback...&lt;br /&gt;
&lt;br /&gt;
I am using a simple calculated question on 2,0 or a calculated question on 1,9  to test the various combinations with different answers and tolerances.&lt;br /&gt;
&lt;br /&gt;
The range (Min- Max ) is available directly.&lt;br /&gt;
&lt;br /&gt;
At first tests your proposal seems to be working.&lt;br /&gt;
&lt;br /&gt;
I will report here the results of various tests on 1,9, actual 2, your proposal and the more linear code.&lt;br /&gt;
&lt;br /&gt;
This should help us to choose which tests to use.&lt;br /&gt;
&lt;br /&gt;
[[User:Pierre Pichet|Pierre Pichet]] 12:38, 16 August 2012 (WST)&lt;br /&gt;
=Tests results=&lt;br /&gt;
Types&lt;br /&gt;
* R :relative &lt;br /&gt;
*N  :nominal &lt;br /&gt;
*G  : geometric&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Answer!!Tolerance !!Type    !! 1,9 Min!! 1,9 Max!! 2,0 Min!! 2,0 Max!! Tim Min!! Tim Max!! Code Min !! Code Max&lt;br /&gt;
|-&lt;br /&gt;
|0          ||  0          ||  N      ||  0        ||  0    ||  -1.0E-14  ||  1.0E-14  || -1.0E-28    ||  1.0E-28 ||  -1.0E-14 ||  1.0E-14      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  1e-24    ||  N    || 0   || 0    ||  -1.0000000001E-14   ||  +1.0000000001E-14   ||  -1.0001E-24    ||  1.0001E-24 ||  -1.0E-24 ||  1.0E-24     &lt;br /&gt;
|-&lt;br /&gt;
|1e-20          ||  0   ||  N ||  cell 1||  cell 2    ||  9.9999999999999E-21   ||  1.0E-20   || 9.9999999999999E-21    ||  1.0E-20 ||  9.9999999999999E-21 ||  1.0E-20     &lt;br /&gt;
|-&lt;br /&gt;
|1e-20          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
The first tests show that Tim proposal does not calculate the 0 answer, 0 Tolerance to the correct value which should be the real number precision here 1*10-14&lt;br /&gt;
The tests on master, Tim proposal and code proposal are done on the same installation just changing the branchs (master) created for the tests so everything else is constant.&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34885</id>
		<title>Question Engine 2:Numerical tolerances</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34885"/>
		<updated>2012-08-16T23:21:13Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: /* Tests results */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Analysis of the various tolerances for numerical and calculated question type answer see (MDL-31837)&lt;br /&gt;
&lt;br /&gt;
In grading a numerical response, the (student) numerical value is compared to the answer numerical value.&lt;br /&gt;
&lt;br /&gt;
This comparison allow a tolerance that is associated with the answer and that can be expressed in various ways.&lt;br /&gt;
&lt;br /&gt;
For calculated question answers the tolerance can be of 3 different types: relative, nominal or geometric. &lt;br /&gt;
=Limits of real numbers in PHP=&lt;br /&gt;
&lt;br /&gt;
The following is from http://www.php.net/manual/en/language.types.float.php&lt;br /&gt;
&lt;br /&gt;
The size of a float is platform-dependent, although a maximum of ~1.8e308 with a precision of roughly 14 decimal digits is a common value (the 64 bit IEEE format).&lt;br /&gt;
&lt;br /&gt;
 Warning&lt;br /&gt;
 Floating point precision&lt;br /&gt;
&lt;br /&gt;
Floating point numbers have limited precision. Although it depends on the system, PHP typically uses the IEEE 754 double precision format, which will give a maximum relative error due to rounding in the order of 1.11e-16. Non elementary arithmetic operations may give larger errors, and, of course, error propagation must be considered when several operations are compounded.&lt;br /&gt;
&lt;br /&gt;
Additionally, rational numbers that are exactly representable as floating point numbers in base 10, like 0.1 or 0.7, do not have an exact representation as floating point numbers in base 2, which is used internally, no matter the size of the mantissa. Hence, they cannot be converted into their internal binary counterparts without a small loss of precision. This can lead to confusing results: for example, floor((0.1+0.7)*10) will usually return 7 instead of the expected 8, since the internal representation will be something like 7.9999999999999991118....&lt;br /&gt;
&lt;br /&gt;
So never trust floating number results to the last digit, and do not compare floating point numbers directly for equality. If higher precision is necessary, the arbitrary precision math functions and gmp functions are available.&lt;br /&gt;
&lt;br /&gt;
Since the internal representation is in base 2, 0 and 1 will have the same exponent so the precision ( i.e. init_get(&#039;precision&#039;) should have the same value.?&lt;br /&gt;
&lt;br /&gt;
....&lt;br /&gt;
=1,9 version=&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
function get_tolerance_interval(&amp;amp;$answer) {&lt;br /&gt;
        // No tolerance&lt;br /&gt;
        if (empty($answer-&amp;gt;tolerance)) {&lt;br /&gt;
            $answer-&amp;gt;tolerance = 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Calculate the interval of correct responses (min/max)&lt;br /&gt;
        if (!isset($answer-&amp;gt;tolerancetype)) {&lt;br /&gt;
            $answer-&amp;gt;tolerancetype = 2; // nominal&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make the&lt;br /&gt;
        // comparison work correctly. Otherwise seemingly equal values can yield&lt;br /&gt;
        // false. (fixes bug #3225)&lt;br /&gt;
        $tolerance = (float)$answer-&amp;gt;tolerance + (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;));&lt;br /&gt;
        switch ($answer-&amp;gt;tolerancetype) {&lt;br /&gt;
            case &#039;1&#039;: case &#039;relative&#039;:&lt;br /&gt;
                /// Recalculate the tolerance and fall through&lt;br /&gt;
                /// to the nominal case:&lt;br /&gt;
                $tolerance = $answer-&amp;gt;answer * $tolerance;&lt;br /&gt;
                // Do not fall through to the nominal case because the tiny fraction is a factor of the answer&lt;br /&gt;
                 $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;2&#039;: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                // $answer-&amp;gt;tolerance 0 or something else&lt;br /&gt;
                if ((float)$answer-&amp;gt;tolerance == 0.0  &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance ){&lt;br /&gt;
                    $tolerance = (float) (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) * abs((float)$answer-&amp;gt;answer) ; //tiny fraction&lt;br /&gt;
                } else if ((float)$answer-&amp;gt;tolerance != 0.0 &amp;amp;&amp;amp; abs((float)$answer-&amp;gt;tolerance) &amp;lt; abs((float)$answer-&amp;gt;answer) &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance){&lt;br /&gt;
                    $tolerance = (1+(&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) )* abs((float) $answer-&amp;gt;tolerance) ;//tiny fraction&lt;br /&gt;
               }&lt;br /&gt;
&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;3&#039;: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                $max = $answer-&amp;gt;answer * $quotient;&lt;br /&gt;
                $min = $answer-&amp;gt;answer / $quotient;&lt;br /&gt;
                break;&lt;br /&gt;
            default:&lt;br /&gt;
                error(&amp;quot;Unknown tolerance type $answer-&amp;gt;tolerancetype&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $answer-&amp;gt;min = $min;&lt;br /&gt;
        $answer-&amp;gt;max = $max;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 actual code=&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class qtype_numerical_answer extends question_answer {&lt;br /&gt;
    /** @var float allowable margin of error. */&lt;br /&gt;
    public $tolerance;&lt;br /&gt;
    /** @var integer|string see {@link get_tolerance_interval()} for the meaning of this value. */&lt;br /&gt;
    public $tolerancetype = 2;&lt;br /&gt;
&lt;br /&gt;
    public function __construct($id, $answer, $fraction, $feedback, $feedbackformat, $tolerance) {&lt;br /&gt;
        parent::__construct($id, $answer, $fraction, $feedback, $feedbackformat);&lt;br /&gt;
        $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_tolerance_interval() {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            throw new coding_exception(&#039;Cannot work out tolerance interval for answer *.&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make&lt;br /&gt;
        // the comparison work correctly, otherwise seemingly equal values can&lt;br /&gt;
        // yield false. See MDL-3225.&lt;br /&gt;
        $tolerance = (float) $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;));&lt;br /&gt;
&lt;br /&gt;
        switch ($this-&amp;gt;tolerancetype) {&lt;br /&gt;
            case 1: case &#039;relative&#039;:&lt;br /&gt;
                $range = abs($this-&amp;gt;answer) * $tolerance;&lt;br /&gt;
                return array($this-&amp;gt;answer - $range, $this-&amp;gt;answer + $range);&lt;br /&gt;
&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) *&lt;br /&gt;
                        max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&lt;br /&gt;
            case 3: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                return array($this-&amp;gt;answer / $quotient, $this-&amp;gt;answer * $quotient);&lt;br /&gt;
&lt;br /&gt;
            default:&lt;br /&gt;
                throw new coding_exception(&#039;Unknown tolerance type &#039; . $this-&amp;gt;tolerancetype);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function within_tolerance($value) {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
        list($min, $max) = $this-&amp;gt;get_tolerance_interval();&lt;br /&gt;
        return $min &amp;lt;= $value &amp;amp;&amp;amp; $value &amp;lt;= $max;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 vs 1,9 differences=&lt;br /&gt;
== case relative ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case geometric ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case nominal ==&lt;br /&gt;
The use of &lt;br /&gt;
 pow(10, -1 * ini_get(&#039;precision&#039;)) * max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
The &#039;tiny fraction&#039; part of the tolerance  is not related to the answer when the answer is less than 1. &lt;br /&gt;
&lt;br /&gt;
We should get back to the 1,9 equivalent code first by removing the max function &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The 1,9 code has a special treatment of the answer == 0 .&lt;br /&gt;
&lt;br /&gt;
Should we keep the code ?&lt;br /&gt;
&lt;br /&gt;
=== Answer is 0===&lt;br /&gt;
What is the precision of 0 ?&lt;br /&gt;
It cannot be 0 , it only can be the precision of the digital part of the number i.e.  pow(10, -1 * ini_get(&#039;precision&#039;)).&lt;br /&gt;
As a mather of fact the exponent part of 0 is the same one as 1 so its precision is the same.&lt;br /&gt;
We should not forget that the &amp;quot;turning point&amp;quot; (positive to negative)  of real number exponent value is 1 not 0.&lt;br /&gt;
&lt;br /&gt;
So to get the &amp;quot;tiny number&amp;quot; we should multiply the  pow(10, -1 * ini_get(&#039;precision&#039;)) by $this-&amp;gt;answer except when $this-&amp;gt;answer == 0 when it should be 1.&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 0,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;pow(10, -1 * ini_get(&#039;precision&#039;))=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
&lt;br /&gt;
=== Answer is NOT 0===&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;tiny part&amp;quot; should mostly be calculated as pow(10, -1 * ini_get(&#039;precision&#039;))*$answer&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 2,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;=pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))** $this-&amp;gt;answer ;&lt;br /&gt;
&lt;br /&gt;
=Code flow proposal=&lt;br /&gt;
&lt;br /&gt;
This code reflects the discussion although a more concise version could be built.&lt;br /&gt;
The proposal is somehow different from the 1,9 version as it includes the precision of the tolerance in the range.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    if ($this-&amp;gt;answer == 0.0){&lt;br /&gt;
         if($this-&amp;gt;tolerance == 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)){ // the 0&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         }&lt;br /&gt;
   } else {&lt;br /&gt;
         if($this-&amp;gt;tolerance === 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;answer ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)* abs($this-&amp;gt;answer)){ &lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
         }     &lt;br /&gt;
   }         &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Tim&#039;s idea==&lt;br /&gt;
&lt;br /&gt;
I am wondering whether it works just change &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the 2.0 code to&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max($this-&amp;gt;tolerance, abs($this-&amp;gt;answer), pow(10, -1 * ini_get(&#039;precision&#039;)));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code might be nicer if we define $epsilon = pow(10, -1 * ini_get(&#039;precision&#039;)) at the start of the function.&lt;br /&gt;
&lt;br /&gt;
Finally, I would like to know what tests you propose to add to question/type/numerical/tests/answer_test.php in order to demonstrate that everything is working properly. In particular, what tests would you like to add that will fail with the current code, but which will pass once we have fixed this bug?&lt;br /&gt;
&lt;br /&gt;
--[[User:Tim Hunt|Tim Hunt]] 00:53, 16 August 2012 (WST)&lt;br /&gt;
==Pierre&#039;s comment==&lt;br /&gt;
Thanks for your code expert feedback...&lt;br /&gt;
&lt;br /&gt;
I am using a simple calculated question on 2,0 or a calculated question on 1,9  to test the various combinations with different answers and tolerances.&lt;br /&gt;
&lt;br /&gt;
The range (Min- Max ) is available directly.&lt;br /&gt;
&lt;br /&gt;
At first tests your proposal seems to be working.&lt;br /&gt;
&lt;br /&gt;
I will report here the results of various tests on 1,9, actual 2, your proposal and the more linear code.&lt;br /&gt;
&lt;br /&gt;
This should help us to choose which tests to use.&lt;br /&gt;
&lt;br /&gt;
[[User:Pierre Pichet|Pierre Pichet]] 12:38, 16 August 2012 (WST)&lt;br /&gt;
=Tests results=&lt;br /&gt;
Types&lt;br /&gt;
* R :relative &lt;br /&gt;
*N  :nominal &lt;br /&gt;
*G  : geometric&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Answer!!Tolerance !!Type    !! 1,9 Min!! 1,9 Max!! 2,0 Min!! 2,0 Max!! Tim Min!! Tim Max!! Code Min !! Code Max&lt;br /&gt;
|-&lt;br /&gt;
|0          ||  0          ||  N      ||  0        ||  0    ||  -1.0E-14  ||  1.0E-14  || -1.0E-28    ||  1.0E-28 ||  -1.0E-14 ||  1.0E-14      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  1e-24    ||  N    || 0   || 0    ||  -1.0000000001E-14   ||  +1.0000000001E-14   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
The first tests show that Tim proposal does not calculate the 0 answer, 0 Tolerance to the correct value which should be the real number precision here 1*10-14&lt;br /&gt;
The tests on master, Tim proposal and code proposal are done on the same installation just changing the branchs (master) created for the tests so everything else is constant.&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34880</id>
		<title>Question Engine 2:Numerical tolerances</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34880"/>
		<updated>2012-08-16T21:36:06Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: /* Tests results */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Analysis of the various tolerances for numerical and calculated question type answer see (MDL-31837)&lt;br /&gt;
&lt;br /&gt;
In grading a numerical response, the (student) numerical value is compared to the answer numerical value.&lt;br /&gt;
&lt;br /&gt;
This comparison allow a tolerance that is associated with the answer and that can be expressed in various ways.&lt;br /&gt;
&lt;br /&gt;
For calculated question answers the tolerance can be of 3 different types: relative, nominal or geometric. &lt;br /&gt;
=Limits of real numbers in PHP=&lt;br /&gt;
&lt;br /&gt;
The following is from http://www.php.net/manual/en/language.types.float.php&lt;br /&gt;
&lt;br /&gt;
The size of a float is platform-dependent, although a maximum of ~1.8e308 with a precision of roughly 14 decimal digits is a common value (the 64 bit IEEE format).&lt;br /&gt;
&lt;br /&gt;
 Warning&lt;br /&gt;
 Floating point precision&lt;br /&gt;
&lt;br /&gt;
Floating point numbers have limited precision. Although it depends on the system, PHP typically uses the IEEE 754 double precision format, which will give a maximum relative error due to rounding in the order of 1.11e-16. Non elementary arithmetic operations may give larger errors, and, of course, error propagation must be considered when several operations are compounded.&lt;br /&gt;
&lt;br /&gt;
Additionally, rational numbers that are exactly representable as floating point numbers in base 10, like 0.1 or 0.7, do not have an exact representation as floating point numbers in base 2, which is used internally, no matter the size of the mantissa. Hence, they cannot be converted into their internal binary counterparts without a small loss of precision. This can lead to confusing results: for example, floor((0.1+0.7)*10) will usually return 7 instead of the expected 8, since the internal representation will be something like 7.9999999999999991118....&lt;br /&gt;
&lt;br /&gt;
So never trust floating number results to the last digit, and do not compare floating point numbers directly for equality. If higher precision is necessary, the arbitrary precision math functions and gmp functions are available.&lt;br /&gt;
&lt;br /&gt;
Since the internal representation is in base 2, 0 and 1 will have the same exponent so the precision ( i.e. init_get(&#039;precision&#039;) should have the same value.?&lt;br /&gt;
&lt;br /&gt;
....&lt;br /&gt;
=1,9 version=&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
function get_tolerance_interval(&amp;amp;$answer) {&lt;br /&gt;
        // No tolerance&lt;br /&gt;
        if (empty($answer-&amp;gt;tolerance)) {&lt;br /&gt;
            $answer-&amp;gt;tolerance = 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Calculate the interval of correct responses (min/max)&lt;br /&gt;
        if (!isset($answer-&amp;gt;tolerancetype)) {&lt;br /&gt;
            $answer-&amp;gt;tolerancetype = 2; // nominal&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make the&lt;br /&gt;
        // comparison work correctly. Otherwise seemingly equal values can yield&lt;br /&gt;
        // false. (fixes bug #3225)&lt;br /&gt;
        $tolerance = (float)$answer-&amp;gt;tolerance + (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;));&lt;br /&gt;
        switch ($answer-&amp;gt;tolerancetype) {&lt;br /&gt;
            case &#039;1&#039;: case &#039;relative&#039;:&lt;br /&gt;
                /// Recalculate the tolerance and fall through&lt;br /&gt;
                /// to the nominal case:&lt;br /&gt;
                $tolerance = $answer-&amp;gt;answer * $tolerance;&lt;br /&gt;
                // Do not fall through to the nominal case because the tiny fraction is a factor of the answer&lt;br /&gt;
                 $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;2&#039;: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                // $answer-&amp;gt;tolerance 0 or something else&lt;br /&gt;
                if ((float)$answer-&amp;gt;tolerance == 0.0  &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance ){&lt;br /&gt;
                    $tolerance = (float) (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) * abs((float)$answer-&amp;gt;answer) ; //tiny fraction&lt;br /&gt;
                } else if ((float)$answer-&amp;gt;tolerance != 0.0 &amp;amp;&amp;amp; abs((float)$answer-&amp;gt;tolerance) &amp;lt; abs((float)$answer-&amp;gt;answer) &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance){&lt;br /&gt;
                    $tolerance = (1+(&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) )* abs((float) $answer-&amp;gt;tolerance) ;//tiny fraction&lt;br /&gt;
               }&lt;br /&gt;
&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;3&#039;: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                $max = $answer-&amp;gt;answer * $quotient;&lt;br /&gt;
                $min = $answer-&amp;gt;answer / $quotient;&lt;br /&gt;
                break;&lt;br /&gt;
            default:&lt;br /&gt;
                error(&amp;quot;Unknown tolerance type $answer-&amp;gt;tolerancetype&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $answer-&amp;gt;min = $min;&lt;br /&gt;
        $answer-&amp;gt;max = $max;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 actual code=&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class qtype_numerical_answer extends question_answer {&lt;br /&gt;
    /** @var float allowable margin of error. */&lt;br /&gt;
    public $tolerance;&lt;br /&gt;
    /** @var integer|string see {@link get_tolerance_interval()} for the meaning of this value. */&lt;br /&gt;
    public $tolerancetype = 2;&lt;br /&gt;
&lt;br /&gt;
    public function __construct($id, $answer, $fraction, $feedback, $feedbackformat, $tolerance) {&lt;br /&gt;
        parent::__construct($id, $answer, $fraction, $feedback, $feedbackformat);&lt;br /&gt;
        $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_tolerance_interval() {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            throw new coding_exception(&#039;Cannot work out tolerance interval for answer *.&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make&lt;br /&gt;
        // the comparison work correctly, otherwise seemingly equal values can&lt;br /&gt;
        // yield false. See MDL-3225.&lt;br /&gt;
        $tolerance = (float) $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;));&lt;br /&gt;
&lt;br /&gt;
        switch ($this-&amp;gt;tolerancetype) {&lt;br /&gt;
            case 1: case &#039;relative&#039;:&lt;br /&gt;
                $range = abs($this-&amp;gt;answer) * $tolerance;&lt;br /&gt;
                return array($this-&amp;gt;answer - $range, $this-&amp;gt;answer + $range);&lt;br /&gt;
&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) *&lt;br /&gt;
                        max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&lt;br /&gt;
            case 3: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                return array($this-&amp;gt;answer / $quotient, $this-&amp;gt;answer * $quotient);&lt;br /&gt;
&lt;br /&gt;
            default:&lt;br /&gt;
                throw new coding_exception(&#039;Unknown tolerance type &#039; . $this-&amp;gt;tolerancetype);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function within_tolerance($value) {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
        list($min, $max) = $this-&amp;gt;get_tolerance_interval();&lt;br /&gt;
        return $min &amp;lt;= $value &amp;amp;&amp;amp; $value &amp;lt;= $max;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 vs 1,9 differences=&lt;br /&gt;
== case relative ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case geometric ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case nominal ==&lt;br /&gt;
The use of &lt;br /&gt;
 pow(10, -1 * ini_get(&#039;precision&#039;)) * max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
The &#039;tiny fraction&#039; part of the tolerance  is not related to the answer when the answer is less than 1. &lt;br /&gt;
&lt;br /&gt;
We should get back to the 1,9 equivalent code first by removing the max function &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The 1,9 code has a special treatment of the answer == 0 .&lt;br /&gt;
&lt;br /&gt;
Should we keep the code ?&lt;br /&gt;
&lt;br /&gt;
=== Answer is 0===&lt;br /&gt;
What is the precision of 0 ?&lt;br /&gt;
It cannot be 0 , it only can be the precision of the digital part of the number i.e.  pow(10, -1 * ini_get(&#039;precision&#039;)).&lt;br /&gt;
As a mather of fact the exponent part of 0 is the same one as 1 so its precision is the same.&lt;br /&gt;
We should not forget that the &amp;quot;turning point&amp;quot; (positive to negative)  of real number exponent value is 1 not 0.&lt;br /&gt;
&lt;br /&gt;
So to get the &amp;quot;tiny number&amp;quot; we should multiply the  pow(10, -1 * ini_get(&#039;precision&#039;)) by $this-&amp;gt;answer except when $this-&amp;gt;answer == 0 when it should be 1.&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 0,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;pow(10, -1 * ini_get(&#039;precision&#039;))=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
&lt;br /&gt;
=== Answer is NOT 0===&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;tiny part&amp;quot; should mostly be calculated as pow(10, -1 * ini_get(&#039;precision&#039;))*$answer&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 2,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;=pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))** $this-&amp;gt;answer ;&lt;br /&gt;
&lt;br /&gt;
=Code flow proposal=&lt;br /&gt;
&lt;br /&gt;
This code reflects the discussion although a more concise version could be built.&lt;br /&gt;
The proposal is somehow different from the 1,9 version as it includes the precision of the tolerance in the range.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    if ($this-&amp;gt;answer == 0.0){&lt;br /&gt;
         if($this-&amp;gt;tolerance == 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)){ // the 0&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         }&lt;br /&gt;
   } else {&lt;br /&gt;
         if($this-&amp;gt;tolerance === 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;answer ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)* abs($this-&amp;gt;answer)){ &lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
         }     &lt;br /&gt;
   }         &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Tim&#039;s idea==&lt;br /&gt;
&lt;br /&gt;
I am wondering whether it works just change &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the 2.0 code to&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max($this-&amp;gt;tolerance, abs($this-&amp;gt;answer), pow(10, -1 * ini_get(&#039;precision&#039;)));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code might be nicer if we define $epsilon = pow(10, -1 * ini_get(&#039;precision&#039;)) at the start of the function.&lt;br /&gt;
&lt;br /&gt;
Finally, I would like to know what tests you propose to add to question/type/numerical/tests/answer_test.php in order to demonstrate that everything is working properly. In particular, what tests would you like to add that will fail with the current code, but which will pass once we have fixed this bug?&lt;br /&gt;
&lt;br /&gt;
--[[User:Tim Hunt|Tim Hunt]] 00:53, 16 August 2012 (WST)&lt;br /&gt;
==Pierre&#039;s comment==&lt;br /&gt;
Thanks for your code expert feedback...&lt;br /&gt;
&lt;br /&gt;
I am using a simple calculated question on 2,0 or a calculated question on 1,9  to test the various combinations with different answers and tolerances.&lt;br /&gt;
&lt;br /&gt;
The range (Min- Max ) is available directly.&lt;br /&gt;
&lt;br /&gt;
At first tests your proposal seems to be working.&lt;br /&gt;
&lt;br /&gt;
I will report here the results of various tests on 1,9, actual 2, your proposal and the more linear code.&lt;br /&gt;
&lt;br /&gt;
This should help us to choose which tests to use.&lt;br /&gt;
&lt;br /&gt;
[[User:Pierre Pichet|Pierre Pichet]] 12:38, 16 August 2012 (WST)&lt;br /&gt;
=Tests results=&lt;br /&gt;
Types&lt;br /&gt;
* R :relative &lt;br /&gt;
*N  :nominal &lt;br /&gt;
*G  : geometric&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Answer!!Tolerance !!Type    !! 1,9 Min!! 1,9 Max!! 2,0 Min!! 2,0 Max!! Tim Min!! Tim Max!! Code Min !! Code Max&lt;br /&gt;
|-&lt;br /&gt;
|0          ||  0          ||  N      ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   || -1.0E-28    ||  1.0E-28 ||  -1.0E-14 ||  1.0E-14      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  1e-24    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
The first tests show that Tim proposal does not calculate the 0 answer, 0 Tolerance to the correct value which should be the real number precision here 1*10-14&lt;br /&gt;
The tests on master, Tim proposal and code proposal are done on the same installation just changing the branchs (master) created for the tests so everything else is constant.&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34879</id>
		<title>Question Engine 2:Numerical tolerances</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34879"/>
		<updated>2012-08-16T21:33:45Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: /* Tests results */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Analysis of the various tolerances for numerical and calculated question type answer see (MDL-31837)&lt;br /&gt;
&lt;br /&gt;
In grading a numerical response, the (student) numerical value is compared to the answer numerical value.&lt;br /&gt;
&lt;br /&gt;
This comparison allow a tolerance that is associated with the answer and that can be expressed in various ways.&lt;br /&gt;
&lt;br /&gt;
For calculated question answers the tolerance can be of 3 different types: relative, nominal or geometric. &lt;br /&gt;
=Limits of real numbers in PHP=&lt;br /&gt;
&lt;br /&gt;
The following is from http://www.php.net/manual/en/language.types.float.php&lt;br /&gt;
&lt;br /&gt;
The size of a float is platform-dependent, although a maximum of ~1.8e308 with a precision of roughly 14 decimal digits is a common value (the 64 bit IEEE format).&lt;br /&gt;
&lt;br /&gt;
 Warning&lt;br /&gt;
 Floating point precision&lt;br /&gt;
&lt;br /&gt;
Floating point numbers have limited precision. Although it depends on the system, PHP typically uses the IEEE 754 double precision format, which will give a maximum relative error due to rounding in the order of 1.11e-16. Non elementary arithmetic operations may give larger errors, and, of course, error propagation must be considered when several operations are compounded.&lt;br /&gt;
&lt;br /&gt;
Additionally, rational numbers that are exactly representable as floating point numbers in base 10, like 0.1 or 0.7, do not have an exact representation as floating point numbers in base 2, which is used internally, no matter the size of the mantissa. Hence, they cannot be converted into their internal binary counterparts without a small loss of precision. This can lead to confusing results: for example, floor((0.1+0.7)*10) will usually return 7 instead of the expected 8, since the internal representation will be something like 7.9999999999999991118....&lt;br /&gt;
&lt;br /&gt;
So never trust floating number results to the last digit, and do not compare floating point numbers directly for equality. If higher precision is necessary, the arbitrary precision math functions and gmp functions are available.&lt;br /&gt;
&lt;br /&gt;
Since the internal representation is in base 2, 0 and 1 will have the same exponent so the precision ( i.e. init_get(&#039;precision&#039;) should have the same value.?&lt;br /&gt;
&lt;br /&gt;
....&lt;br /&gt;
=1,9 version=&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
function get_tolerance_interval(&amp;amp;$answer) {&lt;br /&gt;
        // No tolerance&lt;br /&gt;
        if (empty($answer-&amp;gt;tolerance)) {&lt;br /&gt;
            $answer-&amp;gt;tolerance = 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Calculate the interval of correct responses (min/max)&lt;br /&gt;
        if (!isset($answer-&amp;gt;tolerancetype)) {&lt;br /&gt;
            $answer-&amp;gt;tolerancetype = 2; // nominal&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make the&lt;br /&gt;
        // comparison work correctly. Otherwise seemingly equal values can yield&lt;br /&gt;
        // false. (fixes bug #3225)&lt;br /&gt;
        $tolerance = (float)$answer-&amp;gt;tolerance + (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;));&lt;br /&gt;
        switch ($answer-&amp;gt;tolerancetype) {&lt;br /&gt;
            case &#039;1&#039;: case &#039;relative&#039;:&lt;br /&gt;
                /// Recalculate the tolerance and fall through&lt;br /&gt;
                /// to the nominal case:&lt;br /&gt;
                $tolerance = $answer-&amp;gt;answer * $tolerance;&lt;br /&gt;
                // Do not fall through to the nominal case because the tiny fraction is a factor of the answer&lt;br /&gt;
                 $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;2&#039;: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                // $answer-&amp;gt;tolerance 0 or something else&lt;br /&gt;
                if ((float)$answer-&amp;gt;tolerance == 0.0  &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance ){&lt;br /&gt;
                    $tolerance = (float) (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) * abs((float)$answer-&amp;gt;answer) ; //tiny fraction&lt;br /&gt;
                } else if ((float)$answer-&amp;gt;tolerance != 0.0 &amp;amp;&amp;amp; abs((float)$answer-&amp;gt;tolerance) &amp;lt; abs((float)$answer-&amp;gt;answer) &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance){&lt;br /&gt;
                    $tolerance = (1+(&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) )* abs((float) $answer-&amp;gt;tolerance) ;//tiny fraction&lt;br /&gt;
               }&lt;br /&gt;
&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;3&#039;: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                $max = $answer-&amp;gt;answer * $quotient;&lt;br /&gt;
                $min = $answer-&amp;gt;answer / $quotient;&lt;br /&gt;
                break;&lt;br /&gt;
            default:&lt;br /&gt;
                error(&amp;quot;Unknown tolerance type $answer-&amp;gt;tolerancetype&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $answer-&amp;gt;min = $min;&lt;br /&gt;
        $answer-&amp;gt;max = $max;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 actual code=&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class qtype_numerical_answer extends question_answer {&lt;br /&gt;
    /** @var float allowable margin of error. */&lt;br /&gt;
    public $tolerance;&lt;br /&gt;
    /** @var integer|string see {@link get_tolerance_interval()} for the meaning of this value. */&lt;br /&gt;
    public $tolerancetype = 2;&lt;br /&gt;
&lt;br /&gt;
    public function __construct($id, $answer, $fraction, $feedback, $feedbackformat, $tolerance) {&lt;br /&gt;
        parent::__construct($id, $answer, $fraction, $feedback, $feedbackformat);&lt;br /&gt;
        $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_tolerance_interval() {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            throw new coding_exception(&#039;Cannot work out tolerance interval for answer *.&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make&lt;br /&gt;
        // the comparison work correctly, otherwise seemingly equal values can&lt;br /&gt;
        // yield false. See MDL-3225.&lt;br /&gt;
        $tolerance = (float) $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;));&lt;br /&gt;
&lt;br /&gt;
        switch ($this-&amp;gt;tolerancetype) {&lt;br /&gt;
            case 1: case &#039;relative&#039;:&lt;br /&gt;
                $range = abs($this-&amp;gt;answer) * $tolerance;&lt;br /&gt;
                return array($this-&amp;gt;answer - $range, $this-&amp;gt;answer + $range);&lt;br /&gt;
&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) *&lt;br /&gt;
                        max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&lt;br /&gt;
            case 3: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                return array($this-&amp;gt;answer / $quotient, $this-&amp;gt;answer * $quotient);&lt;br /&gt;
&lt;br /&gt;
            default:&lt;br /&gt;
                throw new coding_exception(&#039;Unknown tolerance type &#039; . $this-&amp;gt;tolerancetype);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function within_tolerance($value) {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
        list($min, $max) = $this-&amp;gt;get_tolerance_interval();&lt;br /&gt;
        return $min &amp;lt;= $value &amp;amp;&amp;amp; $value &amp;lt;= $max;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 vs 1,9 differences=&lt;br /&gt;
== case relative ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case geometric ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case nominal ==&lt;br /&gt;
The use of &lt;br /&gt;
 pow(10, -1 * ini_get(&#039;precision&#039;)) * max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
The &#039;tiny fraction&#039; part of the tolerance  is not related to the answer when the answer is less than 1. &lt;br /&gt;
&lt;br /&gt;
We should get back to the 1,9 equivalent code first by removing the max function &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The 1,9 code has a special treatment of the answer == 0 .&lt;br /&gt;
&lt;br /&gt;
Should we keep the code ?&lt;br /&gt;
&lt;br /&gt;
=== Answer is 0===&lt;br /&gt;
What is the precision of 0 ?&lt;br /&gt;
It cannot be 0 , it only can be the precision of the digital part of the number i.e.  pow(10, -1 * ini_get(&#039;precision&#039;)).&lt;br /&gt;
As a mather of fact the exponent part of 0 is the same one as 1 so its precision is the same.&lt;br /&gt;
We should not forget that the &amp;quot;turning point&amp;quot; (positive to negative)  of real number exponent value is 1 not 0.&lt;br /&gt;
&lt;br /&gt;
So to get the &amp;quot;tiny number&amp;quot; we should multiply the  pow(10, -1 * ini_get(&#039;precision&#039;)) by $this-&amp;gt;answer except when $this-&amp;gt;answer == 0 when it should be 1.&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 0,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;pow(10, -1 * ini_get(&#039;precision&#039;))=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
&lt;br /&gt;
=== Answer is NOT 0===&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;tiny part&amp;quot; should mostly be calculated as pow(10, -1 * ini_get(&#039;precision&#039;))*$answer&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 2,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;=pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))** $this-&amp;gt;answer ;&lt;br /&gt;
&lt;br /&gt;
=Code flow proposal=&lt;br /&gt;
&lt;br /&gt;
This code reflects the discussion although a more concise version could be built.&lt;br /&gt;
The proposal is somehow different from the 1,9 version as it includes the precision of the tolerance in the range.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    if ($this-&amp;gt;answer == 0.0){&lt;br /&gt;
         if($this-&amp;gt;tolerance == 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)){ // the 0&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         }&lt;br /&gt;
   } else {&lt;br /&gt;
         if($this-&amp;gt;tolerance === 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;answer ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)* abs($this-&amp;gt;answer)){ &lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
         }     &lt;br /&gt;
   }         &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Tim&#039;s idea==&lt;br /&gt;
&lt;br /&gt;
I am wondering whether it works just change &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the 2.0 code to&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max($this-&amp;gt;tolerance, abs($this-&amp;gt;answer), pow(10, -1 * ini_get(&#039;precision&#039;)));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code might be nicer if we define $epsilon = pow(10, -1 * ini_get(&#039;precision&#039;)) at the start of the function.&lt;br /&gt;
&lt;br /&gt;
Finally, I would like to know what tests you propose to add to question/type/numerical/tests/answer_test.php in order to demonstrate that everything is working properly. In particular, what tests would you like to add that will fail with the current code, but which will pass once we have fixed this bug?&lt;br /&gt;
&lt;br /&gt;
--[[User:Tim Hunt|Tim Hunt]] 00:53, 16 August 2012 (WST)&lt;br /&gt;
==Pierre&#039;s comment==&lt;br /&gt;
Thanks for your code expert feedback...&lt;br /&gt;
&lt;br /&gt;
I am using a simple calculated question on 2,0 or a calculated question on 1,9  to test the various combinations with different answers and tolerances.&lt;br /&gt;
&lt;br /&gt;
The range (Min- Max ) is available directly.&lt;br /&gt;
&lt;br /&gt;
At first tests your proposal seems to be working.&lt;br /&gt;
&lt;br /&gt;
I will report here the results of various tests on 1,9, actual 2, your proposal and the more linear code.&lt;br /&gt;
&lt;br /&gt;
This should help us to choose which tests to use.&lt;br /&gt;
&lt;br /&gt;
[[User:Pierre Pichet|Pierre Pichet]] 12:38, 16 August 2012 (WST)&lt;br /&gt;
=Tests results=&lt;br /&gt;
Types&lt;br /&gt;
* R :relative &lt;br /&gt;
*N  :nominal &lt;br /&gt;
*G  : geometric&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Answer!!Tolerance !!Type    !! 1,9 Min!! 1,9 Max!! 2,0 Min!! 2,0 Max!! Tim Min!! Tim Max!! Code Min !! Code Max&lt;br /&gt;
|-&lt;br /&gt;
|0          ||  0          ||  N      ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   || -1.0E-28    ||  1.0E-28 ||  -1.0E-14 ||  1.0E-14      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  1e-24    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
The first tests show that Tim ptoposal does not calcualte the 0 answer, 0 Tolerance to the correct value which should be at the number precision here 1*10-4&lt;br /&gt;
The tests on master, Tim proposal and code proposal are done on the same installation just changing the branchs (master) created for the tests so everything else is constant.&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34878</id>
		<title>Question Engine 2:Numerical tolerances</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34878"/>
		<updated>2012-08-16T21:26:27Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: /* Tests results */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Analysis of the various tolerances for numerical and calculated question type answer see (MDL-31837)&lt;br /&gt;
&lt;br /&gt;
In grading a numerical response, the (student) numerical value is compared to the answer numerical value.&lt;br /&gt;
&lt;br /&gt;
This comparison allow a tolerance that is associated with the answer and that can be expressed in various ways.&lt;br /&gt;
&lt;br /&gt;
For calculated question answers the tolerance can be of 3 different types: relative, nominal or geometric. &lt;br /&gt;
=Limits of real numbers in PHP=&lt;br /&gt;
&lt;br /&gt;
The following is from http://www.php.net/manual/en/language.types.float.php&lt;br /&gt;
&lt;br /&gt;
The size of a float is platform-dependent, although a maximum of ~1.8e308 with a precision of roughly 14 decimal digits is a common value (the 64 bit IEEE format).&lt;br /&gt;
&lt;br /&gt;
 Warning&lt;br /&gt;
 Floating point precision&lt;br /&gt;
&lt;br /&gt;
Floating point numbers have limited precision. Although it depends on the system, PHP typically uses the IEEE 754 double precision format, which will give a maximum relative error due to rounding in the order of 1.11e-16. Non elementary arithmetic operations may give larger errors, and, of course, error propagation must be considered when several operations are compounded.&lt;br /&gt;
&lt;br /&gt;
Additionally, rational numbers that are exactly representable as floating point numbers in base 10, like 0.1 or 0.7, do not have an exact representation as floating point numbers in base 2, which is used internally, no matter the size of the mantissa. Hence, they cannot be converted into their internal binary counterparts without a small loss of precision. This can lead to confusing results: for example, floor((0.1+0.7)*10) will usually return 7 instead of the expected 8, since the internal representation will be something like 7.9999999999999991118....&lt;br /&gt;
&lt;br /&gt;
So never trust floating number results to the last digit, and do not compare floating point numbers directly for equality. If higher precision is necessary, the arbitrary precision math functions and gmp functions are available.&lt;br /&gt;
&lt;br /&gt;
Since the internal representation is in base 2, 0 and 1 will have the same exponent so the precision ( i.e. init_get(&#039;precision&#039;) should have the same value.?&lt;br /&gt;
&lt;br /&gt;
....&lt;br /&gt;
=1,9 version=&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
function get_tolerance_interval(&amp;amp;$answer) {&lt;br /&gt;
        // No tolerance&lt;br /&gt;
        if (empty($answer-&amp;gt;tolerance)) {&lt;br /&gt;
            $answer-&amp;gt;tolerance = 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Calculate the interval of correct responses (min/max)&lt;br /&gt;
        if (!isset($answer-&amp;gt;tolerancetype)) {&lt;br /&gt;
            $answer-&amp;gt;tolerancetype = 2; // nominal&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make the&lt;br /&gt;
        // comparison work correctly. Otherwise seemingly equal values can yield&lt;br /&gt;
        // false. (fixes bug #3225)&lt;br /&gt;
        $tolerance = (float)$answer-&amp;gt;tolerance + (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;));&lt;br /&gt;
        switch ($answer-&amp;gt;tolerancetype) {&lt;br /&gt;
            case &#039;1&#039;: case &#039;relative&#039;:&lt;br /&gt;
                /// Recalculate the tolerance and fall through&lt;br /&gt;
                /// to the nominal case:&lt;br /&gt;
                $tolerance = $answer-&amp;gt;answer * $tolerance;&lt;br /&gt;
                // Do not fall through to the nominal case because the tiny fraction is a factor of the answer&lt;br /&gt;
                 $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;2&#039;: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                // $answer-&amp;gt;tolerance 0 or something else&lt;br /&gt;
                if ((float)$answer-&amp;gt;tolerance == 0.0  &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance ){&lt;br /&gt;
                    $tolerance = (float) (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) * abs((float)$answer-&amp;gt;answer) ; //tiny fraction&lt;br /&gt;
                } else if ((float)$answer-&amp;gt;tolerance != 0.0 &amp;amp;&amp;amp; abs((float)$answer-&amp;gt;tolerance) &amp;lt; abs((float)$answer-&amp;gt;answer) &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance){&lt;br /&gt;
                    $tolerance = (1+(&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) )* abs((float) $answer-&amp;gt;tolerance) ;//tiny fraction&lt;br /&gt;
               }&lt;br /&gt;
&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;3&#039;: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                $max = $answer-&amp;gt;answer * $quotient;&lt;br /&gt;
                $min = $answer-&amp;gt;answer / $quotient;&lt;br /&gt;
                break;&lt;br /&gt;
            default:&lt;br /&gt;
                error(&amp;quot;Unknown tolerance type $answer-&amp;gt;tolerancetype&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $answer-&amp;gt;min = $min;&lt;br /&gt;
        $answer-&amp;gt;max = $max;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 actual code=&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class qtype_numerical_answer extends question_answer {&lt;br /&gt;
    /** @var float allowable margin of error. */&lt;br /&gt;
    public $tolerance;&lt;br /&gt;
    /** @var integer|string see {@link get_tolerance_interval()} for the meaning of this value. */&lt;br /&gt;
    public $tolerancetype = 2;&lt;br /&gt;
&lt;br /&gt;
    public function __construct($id, $answer, $fraction, $feedback, $feedbackformat, $tolerance) {&lt;br /&gt;
        parent::__construct($id, $answer, $fraction, $feedback, $feedbackformat);&lt;br /&gt;
        $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_tolerance_interval() {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            throw new coding_exception(&#039;Cannot work out tolerance interval for answer *.&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make&lt;br /&gt;
        // the comparison work correctly, otherwise seemingly equal values can&lt;br /&gt;
        // yield false. See MDL-3225.&lt;br /&gt;
        $tolerance = (float) $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;));&lt;br /&gt;
&lt;br /&gt;
        switch ($this-&amp;gt;tolerancetype) {&lt;br /&gt;
            case 1: case &#039;relative&#039;:&lt;br /&gt;
                $range = abs($this-&amp;gt;answer) * $tolerance;&lt;br /&gt;
                return array($this-&amp;gt;answer - $range, $this-&amp;gt;answer + $range);&lt;br /&gt;
&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) *&lt;br /&gt;
                        max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&lt;br /&gt;
            case 3: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                return array($this-&amp;gt;answer / $quotient, $this-&amp;gt;answer * $quotient);&lt;br /&gt;
&lt;br /&gt;
            default:&lt;br /&gt;
                throw new coding_exception(&#039;Unknown tolerance type &#039; . $this-&amp;gt;tolerancetype);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function within_tolerance($value) {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
        list($min, $max) = $this-&amp;gt;get_tolerance_interval();&lt;br /&gt;
        return $min &amp;lt;= $value &amp;amp;&amp;amp; $value &amp;lt;= $max;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 vs 1,9 differences=&lt;br /&gt;
== case relative ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case geometric ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case nominal ==&lt;br /&gt;
The use of &lt;br /&gt;
 pow(10, -1 * ini_get(&#039;precision&#039;)) * max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
The &#039;tiny fraction&#039; part of the tolerance  is not related to the answer when the answer is less than 1. &lt;br /&gt;
&lt;br /&gt;
We should get back to the 1,9 equivalent code first by removing the max function &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The 1,9 code has a special treatment of the answer == 0 .&lt;br /&gt;
&lt;br /&gt;
Should we keep the code ?&lt;br /&gt;
&lt;br /&gt;
=== Answer is 0===&lt;br /&gt;
What is the precision of 0 ?&lt;br /&gt;
It cannot be 0 , it only can be the precision of the digital part of the number i.e.  pow(10, -1 * ini_get(&#039;precision&#039;)).&lt;br /&gt;
As a mather of fact the exponent part of 0 is the same one as 1 so its precision is the same.&lt;br /&gt;
We should not forget that the &amp;quot;turning point&amp;quot; (positive to negative)  of real number exponent value is 1 not 0.&lt;br /&gt;
&lt;br /&gt;
So to get the &amp;quot;tiny number&amp;quot; we should multiply the  pow(10, -1 * ini_get(&#039;precision&#039;)) by $this-&amp;gt;answer except when $this-&amp;gt;answer == 0 when it should be 1.&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 0,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;pow(10, -1 * ini_get(&#039;precision&#039;))=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
&lt;br /&gt;
=== Answer is NOT 0===&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;tiny part&amp;quot; should mostly be calculated as pow(10, -1 * ini_get(&#039;precision&#039;))*$answer&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 2,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;=pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))** $this-&amp;gt;answer ;&lt;br /&gt;
&lt;br /&gt;
=Code flow proposal=&lt;br /&gt;
&lt;br /&gt;
This code reflects the discussion although a more concise version could be built.&lt;br /&gt;
The proposal is somehow different from the 1,9 version as it includes the precision of the tolerance in the range.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    if ($this-&amp;gt;answer == 0.0){&lt;br /&gt;
         if($this-&amp;gt;tolerance == 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)){ // the 0&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         }&lt;br /&gt;
   } else {&lt;br /&gt;
         if($this-&amp;gt;tolerance === 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;answer ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)* abs($this-&amp;gt;answer)){ &lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
         }     &lt;br /&gt;
   }         &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Tim&#039;s idea==&lt;br /&gt;
&lt;br /&gt;
I am wondering whether it works just change &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the 2.0 code to&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max($this-&amp;gt;tolerance, abs($this-&amp;gt;answer), pow(10, -1 * ini_get(&#039;precision&#039;)));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code might be nicer if we define $epsilon = pow(10, -1 * ini_get(&#039;precision&#039;)) at the start of the function.&lt;br /&gt;
&lt;br /&gt;
Finally, I would like to know what tests you propose to add to question/type/numerical/tests/answer_test.php in order to demonstrate that everything is working properly. In particular, what tests would you like to add that will fail with the current code, but which will pass once we have fixed this bug?&lt;br /&gt;
&lt;br /&gt;
--[[User:Tim Hunt|Tim Hunt]] 00:53, 16 August 2012 (WST)&lt;br /&gt;
==Pierre&#039;s comment==&lt;br /&gt;
Thanks for your code expert feedback...&lt;br /&gt;
&lt;br /&gt;
I am using a simple calculated question on 2,0 or a calculated question on 1,9  to test the various combinations with different answers and tolerances.&lt;br /&gt;
&lt;br /&gt;
The range (Min- Max ) is available directly.&lt;br /&gt;
&lt;br /&gt;
At first tests your proposal seems to be working.&lt;br /&gt;
&lt;br /&gt;
I will report here the results of various tests on 1,9, actual 2, your proposal and the more linear code.&lt;br /&gt;
&lt;br /&gt;
This should help us to choose which tests to use.&lt;br /&gt;
&lt;br /&gt;
[[User:Pierre Pichet|Pierre Pichet]] 12:38, 16 August 2012 (WST)&lt;br /&gt;
=Tests results=&lt;br /&gt;
Types&lt;br /&gt;
* R :relative &lt;br /&gt;
*N  :nominal &lt;br /&gt;
*G  : geometric&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Answer!!Tolerance !!Type    !! 1,9 Min!! 1,9 Max!! 2,0 Min!! 2,0 Max!! Tim Min!! Tim Max!! Code Min !! Code Max&lt;br /&gt;
|-&lt;br /&gt;
|0          ||  0          ||  N      ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   || -1.0E-28    ||  1.0E-28 ||  -1.0E-14 ||  1.0E-14      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  1e-24    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34877</id>
		<title>Question Engine 2:Numerical tolerances</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34877"/>
		<updated>2012-08-16T20:54:05Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: /* Tests results */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Analysis of the various tolerances for numerical and calculated question type answer see (MDL-31837)&lt;br /&gt;
&lt;br /&gt;
In grading a numerical response, the (student) numerical value is compared to the answer numerical value.&lt;br /&gt;
&lt;br /&gt;
This comparison allow a tolerance that is associated with the answer and that can be expressed in various ways.&lt;br /&gt;
&lt;br /&gt;
For calculated question answers the tolerance can be of 3 different types: relative, nominal or geometric. &lt;br /&gt;
=Limits of real numbers in PHP=&lt;br /&gt;
&lt;br /&gt;
The following is from http://www.php.net/manual/en/language.types.float.php&lt;br /&gt;
&lt;br /&gt;
The size of a float is platform-dependent, although a maximum of ~1.8e308 with a precision of roughly 14 decimal digits is a common value (the 64 bit IEEE format).&lt;br /&gt;
&lt;br /&gt;
 Warning&lt;br /&gt;
 Floating point precision&lt;br /&gt;
&lt;br /&gt;
Floating point numbers have limited precision. Although it depends on the system, PHP typically uses the IEEE 754 double precision format, which will give a maximum relative error due to rounding in the order of 1.11e-16. Non elementary arithmetic operations may give larger errors, and, of course, error propagation must be considered when several operations are compounded.&lt;br /&gt;
&lt;br /&gt;
Additionally, rational numbers that are exactly representable as floating point numbers in base 10, like 0.1 or 0.7, do not have an exact representation as floating point numbers in base 2, which is used internally, no matter the size of the mantissa. Hence, they cannot be converted into their internal binary counterparts without a small loss of precision. This can lead to confusing results: for example, floor((0.1+0.7)*10) will usually return 7 instead of the expected 8, since the internal representation will be something like 7.9999999999999991118....&lt;br /&gt;
&lt;br /&gt;
So never trust floating number results to the last digit, and do not compare floating point numbers directly for equality. If higher precision is necessary, the arbitrary precision math functions and gmp functions are available.&lt;br /&gt;
&lt;br /&gt;
Since the internal representation is in base 2, 0 and 1 will have the same exponent so the precision ( i.e. init_get(&#039;precision&#039;) should have the same value.?&lt;br /&gt;
&lt;br /&gt;
....&lt;br /&gt;
=1,9 version=&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
function get_tolerance_interval(&amp;amp;$answer) {&lt;br /&gt;
        // No tolerance&lt;br /&gt;
        if (empty($answer-&amp;gt;tolerance)) {&lt;br /&gt;
            $answer-&amp;gt;tolerance = 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Calculate the interval of correct responses (min/max)&lt;br /&gt;
        if (!isset($answer-&amp;gt;tolerancetype)) {&lt;br /&gt;
            $answer-&amp;gt;tolerancetype = 2; // nominal&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make the&lt;br /&gt;
        // comparison work correctly. Otherwise seemingly equal values can yield&lt;br /&gt;
        // false. (fixes bug #3225)&lt;br /&gt;
        $tolerance = (float)$answer-&amp;gt;tolerance + (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;));&lt;br /&gt;
        switch ($answer-&amp;gt;tolerancetype) {&lt;br /&gt;
            case &#039;1&#039;: case &#039;relative&#039;:&lt;br /&gt;
                /// Recalculate the tolerance and fall through&lt;br /&gt;
                /// to the nominal case:&lt;br /&gt;
                $tolerance = $answer-&amp;gt;answer * $tolerance;&lt;br /&gt;
                // Do not fall through to the nominal case because the tiny fraction is a factor of the answer&lt;br /&gt;
                 $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;2&#039;: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                // $answer-&amp;gt;tolerance 0 or something else&lt;br /&gt;
                if ((float)$answer-&amp;gt;tolerance == 0.0  &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance ){&lt;br /&gt;
                    $tolerance = (float) (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) * abs((float)$answer-&amp;gt;answer) ; //tiny fraction&lt;br /&gt;
                } else if ((float)$answer-&amp;gt;tolerance != 0.0 &amp;amp;&amp;amp; abs((float)$answer-&amp;gt;tolerance) &amp;lt; abs((float)$answer-&amp;gt;answer) &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance){&lt;br /&gt;
                    $tolerance = (1+(&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) )* abs((float) $answer-&amp;gt;tolerance) ;//tiny fraction&lt;br /&gt;
               }&lt;br /&gt;
&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;3&#039;: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                $max = $answer-&amp;gt;answer * $quotient;&lt;br /&gt;
                $min = $answer-&amp;gt;answer / $quotient;&lt;br /&gt;
                break;&lt;br /&gt;
            default:&lt;br /&gt;
                error(&amp;quot;Unknown tolerance type $answer-&amp;gt;tolerancetype&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $answer-&amp;gt;min = $min;&lt;br /&gt;
        $answer-&amp;gt;max = $max;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 actual code=&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class qtype_numerical_answer extends question_answer {&lt;br /&gt;
    /** @var float allowable margin of error. */&lt;br /&gt;
    public $tolerance;&lt;br /&gt;
    /** @var integer|string see {@link get_tolerance_interval()} for the meaning of this value. */&lt;br /&gt;
    public $tolerancetype = 2;&lt;br /&gt;
&lt;br /&gt;
    public function __construct($id, $answer, $fraction, $feedback, $feedbackformat, $tolerance) {&lt;br /&gt;
        parent::__construct($id, $answer, $fraction, $feedback, $feedbackformat);&lt;br /&gt;
        $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_tolerance_interval() {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            throw new coding_exception(&#039;Cannot work out tolerance interval for answer *.&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make&lt;br /&gt;
        // the comparison work correctly, otherwise seemingly equal values can&lt;br /&gt;
        // yield false. See MDL-3225.&lt;br /&gt;
        $tolerance = (float) $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;));&lt;br /&gt;
&lt;br /&gt;
        switch ($this-&amp;gt;tolerancetype) {&lt;br /&gt;
            case 1: case &#039;relative&#039;:&lt;br /&gt;
                $range = abs($this-&amp;gt;answer) * $tolerance;&lt;br /&gt;
                return array($this-&amp;gt;answer - $range, $this-&amp;gt;answer + $range);&lt;br /&gt;
&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) *&lt;br /&gt;
                        max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&lt;br /&gt;
            case 3: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                return array($this-&amp;gt;answer / $quotient, $this-&amp;gt;answer * $quotient);&lt;br /&gt;
&lt;br /&gt;
            default:&lt;br /&gt;
                throw new coding_exception(&#039;Unknown tolerance type &#039; . $this-&amp;gt;tolerancetype);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function within_tolerance($value) {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
        list($min, $max) = $this-&amp;gt;get_tolerance_interval();&lt;br /&gt;
        return $min &amp;lt;= $value &amp;amp;&amp;amp; $value &amp;lt;= $max;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 vs 1,9 differences=&lt;br /&gt;
== case relative ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case geometric ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case nominal ==&lt;br /&gt;
The use of &lt;br /&gt;
 pow(10, -1 * ini_get(&#039;precision&#039;)) * max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
The &#039;tiny fraction&#039; part of the tolerance  is not related to the answer when the answer is less than 1. &lt;br /&gt;
&lt;br /&gt;
We should get back to the 1,9 equivalent code first by removing the max function &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The 1,9 code has a special treatment of the answer == 0 .&lt;br /&gt;
&lt;br /&gt;
Should we keep the code ?&lt;br /&gt;
&lt;br /&gt;
=== Answer is 0===&lt;br /&gt;
What is the precision of 0 ?&lt;br /&gt;
It cannot be 0 , it only can be the precision of the digital part of the number i.e.  pow(10, -1 * ini_get(&#039;precision&#039;)).&lt;br /&gt;
As a mather of fact the exponent part of 0 is the same one as 1 so its precision is the same.&lt;br /&gt;
We should not forget that the &amp;quot;turning point&amp;quot; (positive to negative)  of real number exponent value is 1 not 0.&lt;br /&gt;
&lt;br /&gt;
So to get the &amp;quot;tiny number&amp;quot; we should multiply the  pow(10, -1 * ini_get(&#039;precision&#039;)) by $this-&amp;gt;answer except when $this-&amp;gt;answer == 0 when it should be 1.&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 0,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;pow(10, -1 * ini_get(&#039;precision&#039;))=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
&lt;br /&gt;
=== Answer is NOT 0===&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;tiny part&amp;quot; should mostly be calculated as pow(10, -1 * ini_get(&#039;precision&#039;))*$answer&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 2,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;=pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))** $this-&amp;gt;answer ;&lt;br /&gt;
&lt;br /&gt;
=Code flow proposal=&lt;br /&gt;
&lt;br /&gt;
This code reflects the discussion although a more concise version could be built.&lt;br /&gt;
The proposal is somehow different from the 1,9 version as it includes the precision of the tolerance in the range.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    if ($this-&amp;gt;answer == 0.0){&lt;br /&gt;
         if($this-&amp;gt;tolerance == 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)){ // the 0&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         }&lt;br /&gt;
   } else {&lt;br /&gt;
         if($this-&amp;gt;tolerance === 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;answer ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)* abs($this-&amp;gt;answer)){ &lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
         }     &lt;br /&gt;
   }         &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Tim&#039;s idea==&lt;br /&gt;
&lt;br /&gt;
I am wondering whether it works just change &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the 2.0 code to&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max($this-&amp;gt;tolerance, abs($this-&amp;gt;answer), pow(10, -1 * ini_get(&#039;precision&#039;)));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code might be nicer if we define $epsilon = pow(10, -1 * ini_get(&#039;precision&#039;)) at the start of the function.&lt;br /&gt;
&lt;br /&gt;
Finally, I would like to know what tests you propose to add to question/type/numerical/tests/answer_test.php in order to demonstrate that everything is working properly. In particular, what tests would you like to add that will fail with the current code, but which will pass once we have fixed this bug?&lt;br /&gt;
&lt;br /&gt;
--[[User:Tim Hunt|Tim Hunt]] 00:53, 16 August 2012 (WST)&lt;br /&gt;
==Pierre&#039;s comment==&lt;br /&gt;
Thanks for your code expert feedback...&lt;br /&gt;
&lt;br /&gt;
I am using a simple calculated question on 2,0 or a calculated question on 1,9  to test the various combinations with different answers and tolerances.&lt;br /&gt;
&lt;br /&gt;
The range (Min- Max ) is available directly.&lt;br /&gt;
&lt;br /&gt;
At first tests your proposal seems to be working.&lt;br /&gt;
&lt;br /&gt;
I will report here the results of various tests on 1,9, actual 2, your proposal and the more linear code.&lt;br /&gt;
&lt;br /&gt;
This should help us to choose which tests to use.&lt;br /&gt;
&lt;br /&gt;
[[User:Pierre Pichet|Pierre Pichet]] 12:38, 16 August 2012 (WST)&lt;br /&gt;
=Tests results=&lt;br /&gt;
Types&lt;br /&gt;
* R :relative &lt;br /&gt;
*N  :nominal &lt;br /&gt;
*G  : geometric&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Answer!!Tolerance !!Type    !! 1,9 Min!! 1,9 Max!! 2,0 Min!! 2,0 Max!! Tim Min!! Tim Max!! Code Min !! Code Max&lt;br /&gt;
|-&lt;br /&gt;
|0          ||  0          ||  N      ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   || -1.0E-28    ||  1.0E-28 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34876</id>
		<title>Question Engine 2:Numerical tolerances</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34876"/>
		<updated>2012-08-16T20:48:54Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: /* Tests results */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Analysis of the various tolerances for numerical and calculated question type answer see (MDL-31837)&lt;br /&gt;
&lt;br /&gt;
In grading a numerical response, the (student) numerical value is compared to the answer numerical value.&lt;br /&gt;
&lt;br /&gt;
This comparison allow a tolerance that is associated with the answer and that can be expressed in various ways.&lt;br /&gt;
&lt;br /&gt;
For calculated question answers the tolerance can be of 3 different types: relative, nominal or geometric. &lt;br /&gt;
=Limits of real numbers in PHP=&lt;br /&gt;
&lt;br /&gt;
The following is from http://www.php.net/manual/en/language.types.float.php&lt;br /&gt;
&lt;br /&gt;
The size of a float is platform-dependent, although a maximum of ~1.8e308 with a precision of roughly 14 decimal digits is a common value (the 64 bit IEEE format).&lt;br /&gt;
&lt;br /&gt;
 Warning&lt;br /&gt;
 Floating point precision&lt;br /&gt;
&lt;br /&gt;
Floating point numbers have limited precision. Although it depends on the system, PHP typically uses the IEEE 754 double precision format, which will give a maximum relative error due to rounding in the order of 1.11e-16. Non elementary arithmetic operations may give larger errors, and, of course, error propagation must be considered when several operations are compounded.&lt;br /&gt;
&lt;br /&gt;
Additionally, rational numbers that are exactly representable as floating point numbers in base 10, like 0.1 or 0.7, do not have an exact representation as floating point numbers in base 2, which is used internally, no matter the size of the mantissa. Hence, they cannot be converted into their internal binary counterparts without a small loss of precision. This can lead to confusing results: for example, floor((0.1+0.7)*10) will usually return 7 instead of the expected 8, since the internal representation will be something like 7.9999999999999991118....&lt;br /&gt;
&lt;br /&gt;
So never trust floating number results to the last digit, and do not compare floating point numbers directly for equality. If higher precision is necessary, the arbitrary precision math functions and gmp functions are available.&lt;br /&gt;
&lt;br /&gt;
Since the internal representation is in base 2, 0 and 1 will have the same exponent so the precision ( i.e. init_get(&#039;precision&#039;) should have the same value.?&lt;br /&gt;
&lt;br /&gt;
....&lt;br /&gt;
=1,9 version=&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
function get_tolerance_interval(&amp;amp;$answer) {&lt;br /&gt;
        // No tolerance&lt;br /&gt;
        if (empty($answer-&amp;gt;tolerance)) {&lt;br /&gt;
            $answer-&amp;gt;tolerance = 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Calculate the interval of correct responses (min/max)&lt;br /&gt;
        if (!isset($answer-&amp;gt;tolerancetype)) {&lt;br /&gt;
            $answer-&amp;gt;tolerancetype = 2; // nominal&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make the&lt;br /&gt;
        // comparison work correctly. Otherwise seemingly equal values can yield&lt;br /&gt;
        // false. (fixes bug #3225)&lt;br /&gt;
        $tolerance = (float)$answer-&amp;gt;tolerance + (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;));&lt;br /&gt;
        switch ($answer-&amp;gt;tolerancetype) {&lt;br /&gt;
            case &#039;1&#039;: case &#039;relative&#039;:&lt;br /&gt;
                /// Recalculate the tolerance and fall through&lt;br /&gt;
                /// to the nominal case:&lt;br /&gt;
                $tolerance = $answer-&amp;gt;answer * $tolerance;&lt;br /&gt;
                // Do not fall through to the nominal case because the tiny fraction is a factor of the answer&lt;br /&gt;
                 $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;2&#039;: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                // $answer-&amp;gt;tolerance 0 or something else&lt;br /&gt;
                if ((float)$answer-&amp;gt;tolerance == 0.0  &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance ){&lt;br /&gt;
                    $tolerance = (float) (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) * abs((float)$answer-&amp;gt;answer) ; //tiny fraction&lt;br /&gt;
                } else if ((float)$answer-&amp;gt;tolerance != 0.0 &amp;amp;&amp;amp; abs((float)$answer-&amp;gt;tolerance) &amp;lt; abs((float)$answer-&amp;gt;answer) &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance){&lt;br /&gt;
                    $tolerance = (1+(&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) )* abs((float) $answer-&amp;gt;tolerance) ;//tiny fraction&lt;br /&gt;
               }&lt;br /&gt;
&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;3&#039;: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                $max = $answer-&amp;gt;answer * $quotient;&lt;br /&gt;
                $min = $answer-&amp;gt;answer / $quotient;&lt;br /&gt;
                break;&lt;br /&gt;
            default:&lt;br /&gt;
                error(&amp;quot;Unknown tolerance type $answer-&amp;gt;tolerancetype&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $answer-&amp;gt;min = $min;&lt;br /&gt;
        $answer-&amp;gt;max = $max;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 actual code=&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class qtype_numerical_answer extends question_answer {&lt;br /&gt;
    /** @var float allowable margin of error. */&lt;br /&gt;
    public $tolerance;&lt;br /&gt;
    /** @var integer|string see {@link get_tolerance_interval()} for the meaning of this value. */&lt;br /&gt;
    public $tolerancetype = 2;&lt;br /&gt;
&lt;br /&gt;
    public function __construct($id, $answer, $fraction, $feedback, $feedbackformat, $tolerance) {&lt;br /&gt;
        parent::__construct($id, $answer, $fraction, $feedback, $feedbackformat);&lt;br /&gt;
        $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_tolerance_interval() {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            throw new coding_exception(&#039;Cannot work out tolerance interval for answer *.&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make&lt;br /&gt;
        // the comparison work correctly, otherwise seemingly equal values can&lt;br /&gt;
        // yield false. See MDL-3225.&lt;br /&gt;
        $tolerance = (float) $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;));&lt;br /&gt;
&lt;br /&gt;
        switch ($this-&amp;gt;tolerancetype) {&lt;br /&gt;
            case 1: case &#039;relative&#039;:&lt;br /&gt;
                $range = abs($this-&amp;gt;answer) * $tolerance;&lt;br /&gt;
                return array($this-&amp;gt;answer - $range, $this-&amp;gt;answer + $range);&lt;br /&gt;
&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) *&lt;br /&gt;
                        max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&lt;br /&gt;
            case 3: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                return array($this-&amp;gt;answer / $quotient, $this-&amp;gt;answer * $quotient);&lt;br /&gt;
&lt;br /&gt;
            default:&lt;br /&gt;
                throw new coding_exception(&#039;Unknown tolerance type &#039; . $this-&amp;gt;tolerancetype);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function within_tolerance($value) {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
        list($min, $max) = $this-&amp;gt;get_tolerance_interval();&lt;br /&gt;
        return $min &amp;lt;= $value &amp;amp;&amp;amp; $value &amp;lt;= $max;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 vs 1,9 differences=&lt;br /&gt;
== case relative ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case geometric ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case nominal ==&lt;br /&gt;
The use of &lt;br /&gt;
 pow(10, -1 * ini_get(&#039;precision&#039;)) * max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
The &#039;tiny fraction&#039; part of the tolerance  is not related to the answer when the answer is less than 1. &lt;br /&gt;
&lt;br /&gt;
We should get back to the 1,9 equivalent code first by removing the max function &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The 1,9 code has a special treatment of the answer == 0 .&lt;br /&gt;
&lt;br /&gt;
Should we keep the code ?&lt;br /&gt;
&lt;br /&gt;
=== Answer is 0===&lt;br /&gt;
What is the precision of 0 ?&lt;br /&gt;
It cannot be 0 , it only can be the precision of the digital part of the number i.e.  pow(10, -1 * ini_get(&#039;precision&#039;)).&lt;br /&gt;
As a mather of fact the exponent part of 0 is the same one as 1 so its precision is the same.&lt;br /&gt;
We should not forget that the &amp;quot;turning point&amp;quot; (positive to negative)  of real number exponent value is 1 not 0.&lt;br /&gt;
&lt;br /&gt;
So to get the &amp;quot;tiny number&amp;quot; we should multiply the  pow(10, -1 * ini_get(&#039;precision&#039;)) by $this-&amp;gt;answer except when $this-&amp;gt;answer == 0 when it should be 1.&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 0,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;pow(10, -1 * ini_get(&#039;precision&#039;))=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
&lt;br /&gt;
=== Answer is NOT 0===&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;tiny part&amp;quot; should mostly be calculated as pow(10, -1 * ini_get(&#039;precision&#039;))*$answer&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 2,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;=pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))** $this-&amp;gt;answer ;&lt;br /&gt;
&lt;br /&gt;
=Code flow proposal=&lt;br /&gt;
&lt;br /&gt;
This code reflects the discussion although a more concise version could be built.&lt;br /&gt;
The proposal is somehow different from the 1,9 version as it includes the precision of the tolerance in the range.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    if ($this-&amp;gt;answer == 0.0){&lt;br /&gt;
         if($this-&amp;gt;tolerance == 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)){ // the 0&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         }&lt;br /&gt;
   } else {&lt;br /&gt;
         if($this-&amp;gt;tolerance === 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;answer ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)* abs($this-&amp;gt;answer)){ &lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
         }     &lt;br /&gt;
   }         &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Tim&#039;s idea==&lt;br /&gt;
&lt;br /&gt;
I am wondering whether it works just change &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the 2.0 code to&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max($this-&amp;gt;tolerance, abs($this-&amp;gt;answer), pow(10, -1 * ini_get(&#039;precision&#039;)));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code might be nicer if we define $epsilon = pow(10, -1 * ini_get(&#039;precision&#039;)) at the start of the function.&lt;br /&gt;
&lt;br /&gt;
Finally, I would like to know what tests you propose to add to question/type/numerical/tests/answer_test.php in order to demonstrate that everything is working properly. In particular, what tests would you like to add that will fail with the current code, but which will pass once we have fixed this bug?&lt;br /&gt;
&lt;br /&gt;
--[[User:Tim Hunt|Tim Hunt]] 00:53, 16 August 2012 (WST)&lt;br /&gt;
==Pierre&#039;s comment==&lt;br /&gt;
Thanks for your code expert feedback...&lt;br /&gt;
&lt;br /&gt;
I am using a simple calculated question on 2,0 or a calculated question on 1,9  to test the various combinations with different answers and tolerances.&lt;br /&gt;
&lt;br /&gt;
The range (Min- Max ) is available directly.&lt;br /&gt;
&lt;br /&gt;
At first tests your proposal seems to be working.&lt;br /&gt;
&lt;br /&gt;
I will report here the results of various tests on 1,9, actual 2, your proposal and the more linear code.&lt;br /&gt;
&lt;br /&gt;
This should help us to choose which tests to use.&lt;br /&gt;
&lt;br /&gt;
[[User:Pierre Pichet|Pierre Pichet]] 12:38, 16 August 2012 (WST)&lt;br /&gt;
=Tests results=&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Answer!!Tolerance !!Type    !! 1,9 Min!! 1,9 Max!! 2,0 Min!! 2,0 Max!! Tim Min!! Tim Max!! Code Min !! Code Max&lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
|-&lt;br /&gt;
|0          ||  cell 2    ||  cell 3 ||  cell 1||  cell 2    ||  cell 3   ||  cell 1   ||  cell 2    ||  cell 3 ||  cell 1 ||  cell 1      &lt;br /&gt;
&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34870</id>
		<title>Question Engine 2:Numerical tolerances</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34870"/>
		<updated>2012-08-16T07:16:39Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: /* Tests results */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Analysis of the various tolerances for numerical and calculated question type answer see (MDL-31837)&lt;br /&gt;
&lt;br /&gt;
In grading a numerical response, the (student) numerical value is compared to the answer numerical value.&lt;br /&gt;
&lt;br /&gt;
This comparison allow a tolerance that is associated with the answer and that can be expressed in various ways.&lt;br /&gt;
&lt;br /&gt;
For calculated question answers the tolerance can be of 3 different types: relative, nominal or geometric. &lt;br /&gt;
=Limits of real numbers in PHP=&lt;br /&gt;
&lt;br /&gt;
The following is from http://www.php.net/manual/en/language.types.float.php&lt;br /&gt;
&lt;br /&gt;
The size of a float is platform-dependent, although a maximum of ~1.8e308 with a precision of roughly 14 decimal digits is a common value (the 64 bit IEEE format).&lt;br /&gt;
&lt;br /&gt;
 Warning&lt;br /&gt;
 Floating point precision&lt;br /&gt;
&lt;br /&gt;
Floating point numbers have limited precision. Although it depends on the system, PHP typically uses the IEEE 754 double precision format, which will give a maximum relative error due to rounding in the order of 1.11e-16. Non elementary arithmetic operations may give larger errors, and, of course, error propagation must be considered when several operations are compounded.&lt;br /&gt;
&lt;br /&gt;
Additionally, rational numbers that are exactly representable as floating point numbers in base 10, like 0.1 or 0.7, do not have an exact representation as floating point numbers in base 2, which is used internally, no matter the size of the mantissa. Hence, they cannot be converted into their internal binary counterparts without a small loss of precision. This can lead to confusing results: for example, floor((0.1+0.7)*10) will usually return 7 instead of the expected 8, since the internal representation will be something like 7.9999999999999991118....&lt;br /&gt;
&lt;br /&gt;
So never trust floating number results to the last digit, and do not compare floating point numbers directly for equality. If higher precision is necessary, the arbitrary precision math functions and gmp functions are available.&lt;br /&gt;
&lt;br /&gt;
Since the internal representation is in base 2, 0 and 1 will have the same exponent so the precision ( i.e. init_get(&#039;precision&#039;) should have the same value.?&lt;br /&gt;
&lt;br /&gt;
....&lt;br /&gt;
=1,9 version=&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
function get_tolerance_interval(&amp;amp;$answer) {&lt;br /&gt;
        // No tolerance&lt;br /&gt;
        if (empty($answer-&amp;gt;tolerance)) {&lt;br /&gt;
            $answer-&amp;gt;tolerance = 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Calculate the interval of correct responses (min/max)&lt;br /&gt;
        if (!isset($answer-&amp;gt;tolerancetype)) {&lt;br /&gt;
            $answer-&amp;gt;tolerancetype = 2; // nominal&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make the&lt;br /&gt;
        // comparison work correctly. Otherwise seemingly equal values can yield&lt;br /&gt;
        // false. (fixes bug #3225)&lt;br /&gt;
        $tolerance = (float)$answer-&amp;gt;tolerance + (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;));&lt;br /&gt;
        switch ($answer-&amp;gt;tolerancetype) {&lt;br /&gt;
            case &#039;1&#039;: case &#039;relative&#039;:&lt;br /&gt;
                /// Recalculate the tolerance and fall through&lt;br /&gt;
                /// to the nominal case:&lt;br /&gt;
                $tolerance = $answer-&amp;gt;answer * $tolerance;&lt;br /&gt;
                // Do not fall through to the nominal case because the tiny fraction is a factor of the answer&lt;br /&gt;
                 $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;2&#039;: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                // $answer-&amp;gt;tolerance 0 or something else&lt;br /&gt;
                if ((float)$answer-&amp;gt;tolerance == 0.0  &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance ){&lt;br /&gt;
                    $tolerance = (float) (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) * abs((float)$answer-&amp;gt;answer) ; //tiny fraction&lt;br /&gt;
                } else if ((float)$answer-&amp;gt;tolerance != 0.0 &amp;amp;&amp;amp; abs((float)$answer-&amp;gt;tolerance) &amp;lt; abs((float)$answer-&amp;gt;answer) &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance){&lt;br /&gt;
                    $tolerance = (1+(&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) )* abs((float) $answer-&amp;gt;tolerance) ;//tiny fraction&lt;br /&gt;
               }&lt;br /&gt;
&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;3&#039;: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                $max = $answer-&amp;gt;answer * $quotient;&lt;br /&gt;
                $min = $answer-&amp;gt;answer / $quotient;&lt;br /&gt;
                break;&lt;br /&gt;
            default:&lt;br /&gt;
                error(&amp;quot;Unknown tolerance type $answer-&amp;gt;tolerancetype&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $answer-&amp;gt;min = $min;&lt;br /&gt;
        $answer-&amp;gt;max = $max;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 actual code=&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class qtype_numerical_answer extends question_answer {&lt;br /&gt;
    /** @var float allowable margin of error. */&lt;br /&gt;
    public $tolerance;&lt;br /&gt;
    /** @var integer|string see {@link get_tolerance_interval()} for the meaning of this value. */&lt;br /&gt;
    public $tolerancetype = 2;&lt;br /&gt;
&lt;br /&gt;
    public function __construct($id, $answer, $fraction, $feedback, $feedbackformat, $tolerance) {&lt;br /&gt;
        parent::__construct($id, $answer, $fraction, $feedback, $feedbackformat);&lt;br /&gt;
        $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_tolerance_interval() {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            throw new coding_exception(&#039;Cannot work out tolerance interval for answer *.&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make&lt;br /&gt;
        // the comparison work correctly, otherwise seemingly equal values can&lt;br /&gt;
        // yield false. See MDL-3225.&lt;br /&gt;
        $tolerance = (float) $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;));&lt;br /&gt;
&lt;br /&gt;
        switch ($this-&amp;gt;tolerancetype) {&lt;br /&gt;
            case 1: case &#039;relative&#039;:&lt;br /&gt;
                $range = abs($this-&amp;gt;answer) * $tolerance;&lt;br /&gt;
                return array($this-&amp;gt;answer - $range, $this-&amp;gt;answer + $range);&lt;br /&gt;
&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) *&lt;br /&gt;
                        max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&lt;br /&gt;
            case 3: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                return array($this-&amp;gt;answer / $quotient, $this-&amp;gt;answer * $quotient);&lt;br /&gt;
&lt;br /&gt;
            default:&lt;br /&gt;
                throw new coding_exception(&#039;Unknown tolerance type &#039; . $this-&amp;gt;tolerancetype);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function within_tolerance($value) {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
        list($min, $max) = $this-&amp;gt;get_tolerance_interval();&lt;br /&gt;
        return $min &amp;lt;= $value &amp;amp;&amp;amp; $value &amp;lt;= $max;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 vs 1,9 differences=&lt;br /&gt;
== case relative ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case geometric ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case nominal ==&lt;br /&gt;
The use of &lt;br /&gt;
 pow(10, -1 * ini_get(&#039;precision&#039;)) * max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
The &#039;tiny fraction&#039; part of the tolerance  is not related to the answer when the answer is less than 1. &lt;br /&gt;
&lt;br /&gt;
We should get back to the 1,9 equivalent code first by removing the max function &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The 1,9 code has a special treatment of the answer == 0 .&lt;br /&gt;
&lt;br /&gt;
Should we keep the code ?&lt;br /&gt;
&lt;br /&gt;
=== Answer is 0===&lt;br /&gt;
What is the precision of 0 ?&lt;br /&gt;
It cannot be 0 , it only can be the precision of the digital part of the number i.e.  pow(10, -1 * ini_get(&#039;precision&#039;)).&lt;br /&gt;
As a mather of fact the exponent part of 0 is the same one as 1 so its precision is the same.&lt;br /&gt;
We should not forget that the &amp;quot;turning point&amp;quot; (positive to negative)  of real number exponent value is 1 not 0.&lt;br /&gt;
&lt;br /&gt;
So to get the &amp;quot;tiny number&amp;quot; we should multiply the  pow(10, -1 * ini_get(&#039;precision&#039;)) by $this-&amp;gt;answer except when $this-&amp;gt;answer == 0 when it should be 1.&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 0,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;pow(10, -1 * ini_get(&#039;precision&#039;))=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
&lt;br /&gt;
=== Answer is NOT 0===&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;tiny part&amp;quot; should mostly be calculated as pow(10, -1 * ini_get(&#039;precision&#039;))*$answer&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 2,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;=pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))** $this-&amp;gt;answer ;&lt;br /&gt;
&lt;br /&gt;
=Code flow proposal=&lt;br /&gt;
&lt;br /&gt;
This code reflects the discussion although a more concise version could be built.&lt;br /&gt;
The proposal is somehow different from the 1,9 version as it includes the precision of the tolerance in the range.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    if ($this-&amp;gt;answer == 0.0){&lt;br /&gt;
         if($this-&amp;gt;tolerance == 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)){ // the 0&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         }&lt;br /&gt;
   } else {&lt;br /&gt;
         if($this-&amp;gt;tolerance === 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;answer ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)* abs($this-&amp;gt;answer)){ &lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
         }     &lt;br /&gt;
   }         &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Tim&#039;s idea==&lt;br /&gt;
&lt;br /&gt;
I am wondering whether it works just change &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the 2.0 code to&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max($this-&amp;gt;tolerance, abs($this-&amp;gt;answer), pow(10, -1 * ini_get(&#039;precision&#039;)));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code might be nicer if we define $epsilon = pow(10, -1 * ini_get(&#039;precision&#039;)) at the start of the function.&lt;br /&gt;
&lt;br /&gt;
Finally, I would like to know what tests you propose to add to question/type/numerical/tests/answer_test.php in order to demonstrate that everything is working properly. In particular, what tests would you like to add that will fail with the current code, but which will pass once we have fixed this bug?&lt;br /&gt;
&lt;br /&gt;
--[[User:Tim Hunt|Tim Hunt]] 00:53, 16 August 2012 (WST)&lt;br /&gt;
==Pierre&#039;s comment==&lt;br /&gt;
Thanks for your code expert feedback...&lt;br /&gt;
&lt;br /&gt;
I am using a simple calculated question on 2,0 or a calculated question on 1,9  to test the various combinations with different answers and tolerances.&lt;br /&gt;
&lt;br /&gt;
The range (Min- Max ) is available directly.&lt;br /&gt;
&lt;br /&gt;
At first tests your proposal seems to be working.&lt;br /&gt;
&lt;br /&gt;
I will report here the results of various tests on 1,9, actual 2, your proposal and the more linear code.&lt;br /&gt;
&lt;br /&gt;
This should help us to choose which tests to use.&lt;br /&gt;
&lt;br /&gt;
[[User:Pierre Pichet|Pierre Pichet]] 12:38, 16 August 2012 (WST)&lt;br /&gt;
=Tests results=&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Answer&lt;br /&gt;
!Tolerance&lt;br /&gt;
!Type&lt;br /&gt;
! 1,9 Min&lt;br /&gt;
! 1,9 Max&lt;br /&gt;
! 2,0 Min&lt;br /&gt;
! 2,0 Max&lt;br /&gt;
! Tim Min&lt;br /&gt;
! Tim Max&lt;br /&gt;
! Code Min &lt;br /&gt;
! Code Max&lt;br /&gt;
|-&lt;br /&gt;
| cell 1&lt;br /&gt;
|  cell 2&lt;br /&gt;
|  cell 3&lt;br /&gt;
| cell 1&lt;br /&gt;
| cell 1&lt;br /&gt;
|  cell 1&lt;br /&gt;
|  cell 1&lt;br /&gt;
|  cell 1&lt;br /&gt;
|  cell 1&lt;br /&gt;
|  cell 1&lt;br /&gt;
|  cell 1&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| cell 1&lt;br /&gt;
|  cell 2&lt;br /&gt;
|  cell 3&lt;br /&gt;
| cell 1&lt;br /&gt;
| cell 1&lt;br /&gt;
|  cell 1&lt;br /&gt;
|  cell 1&lt;br /&gt;
|  cell 1&lt;br /&gt;
|  cell 1&lt;br /&gt;
|  cell 1&lt;br /&gt;
|  cell 1&lt;br /&gt;
|-&lt;br /&gt;
| cell 1&lt;br /&gt;
|  cell 2&lt;br /&gt;
|  cell 3&lt;br /&gt;
| cell 1&lt;br /&gt;
| cell 1&lt;br /&gt;
|  cell 1&lt;br /&gt;
|  cell 1&lt;br /&gt;
|  cell 1&lt;br /&gt;
|  cell 1&lt;br /&gt;
|  cell 1&lt;br /&gt;
|  cell 1&lt;br /&gt;
|-&lt;br /&gt;
| cell 1&lt;br /&gt;
|  cell 2&lt;br /&gt;
|  cell 3&lt;br /&gt;
| cell 1&lt;br /&gt;
| cell 1&lt;br /&gt;
|  cell 1&lt;br /&gt;
|  cell 1&lt;br /&gt;
|  cell 1&lt;br /&gt;
|  cell 1&lt;br /&gt;
|  cell 1&lt;br /&gt;
|  cell 1&lt;br /&gt;
|-&lt;br /&gt;
| cell 1&lt;br /&gt;
|  cell 2&lt;br /&gt;
|  cell 3&lt;br /&gt;
| cell 1&lt;br /&gt;
| cell 1&lt;br /&gt;
|  cell 1&lt;br /&gt;
|  cell 1&lt;br /&gt;
|  cell 1&lt;br /&gt;
|  cell 1&lt;br /&gt;
|  cell 1&lt;br /&gt;
|  cell 1&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
|  &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
|  &lt;br /&gt;
|  &lt;br /&gt;
|  &lt;br /&gt;
|  &lt;br /&gt;
| &lt;br /&gt;
| c&lt;br /&gt;
|-&lt;br /&gt;
| dd&lt;br /&gt;
|  &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
|  &lt;br /&gt;
|  &lt;br /&gt;
|  &lt;br /&gt;
|  &lt;br /&gt;
|&lt;br /&gt;
|  &lt;br /&gt;
|-&lt;br /&gt;
|e-&lt;br /&gt;
| &lt;br /&gt;
|  &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
|  &lt;br /&gt;
|  &lt;br /&gt;
|  &lt;br /&gt;
|  &lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|f &lt;br /&gt;
|  &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
|  &lt;br /&gt;
|  &lt;br /&gt;
|  &lt;br /&gt;
|  &lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34869</id>
		<title>Question Engine 2:Numerical tolerances</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34869"/>
		<updated>2012-08-16T06:57:34Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: /* Pierre&amp;#039;s comment */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Analysis of the various tolerances for numerical and calculated question type answer see (MDL-31837)&lt;br /&gt;
&lt;br /&gt;
In grading a numerical response, the (student) numerical value is compared to the answer numerical value.&lt;br /&gt;
&lt;br /&gt;
This comparison allow a tolerance that is associated with the answer and that can be expressed in various ways.&lt;br /&gt;
&lt;br /&gt;
For calculated question answers the tolerance can be of 3 different types: relative, nominal or geometric. &lt;br /&gt;
=Limits of real numbers in PHP=&lt;br /&gt;
&lt;br /&gt;
The following is from http://www.php.net/manual/en/language.types.float.php&lt;br /&gt;
&lt;br /&gt;
The size of a float is platform-dependent, although a maximum of ~1.8e308 with a precision of roughly 14 decimal digits is a common value (the 64 bit IEEE format).&lt;br /&gt;
&lt;br /&gt;
 Warning&lt;br /&gt;
 Floating point precision&lt;br /&gt;
&lt;br /&gt;
Floating point numbers have limited precision. Although it depends on the system, PHP typically uses the IEEE 754 double precision format, which will give a maximum relative error due to rounding in the order of 1.11e-16. Non elementary arithmetic operations may give larger errors, and, of course, error propagation must be considered when several operations are compounded.&lt;br /&gt;
&lt;br /&gt;
Additionally, rational numbers that are exactly representable as floating point numbers in base 10, like 0.1 or 0.7, do not have an exact representation as floating point numbers in base 2, which is used internally, no matter the size of the mantissa. Hence, they cannot be converted into their internal binary counterparts without a small loss of precision. This can lead to confusing results: for example, floor((0.1+0.7)*10) will usually return 7 instead of the expected 8, since the internal representation will be something like 7.9999999999999991118....&lt;br /&gt;
&lt;br /&gt;
So never trust floating number results to the last digit, and do not compare floating point numbers directly for equality. If higher precision is necessary, the arbitrary precision math functions and gmp functions are available.&lt;br /&gt;
&lt;br /&gt;
Since the internal representation is in base 2, 0 and 1 will have the same exponent so the precision ( i.e. init_get(&#039;precision&#039;) should have the same value.?&lt;br /&gt;
&lt;br /&gt;
....&lt;br /&gt;
=1,9 version=&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
function get_tolerance_interval(&amp;amp;$answer) {&lt;br /&gt;
        // No tolerance&lt;br /&gt;
        if (empty($answer-&amp;gt;tolerance)) {&lt;br /&gt;
            $answer-&amp;gt;tolerance = 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Calculate the interval of correct responses (min/max)&lt;br /&gt;
        if (!isset($answer-&amp;gt;tolerancetype)) {&lt;br /&gt;
            $answer-&amp;gt;tolerancetype = 2; // nominal&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make the&lt;br /&gt;
        // comparison work correctly. Otherwise seemingly equal values can yield&lt;br /&gt;
        // false. (fixes bug #3225)&lt;br /&gt;
        $tolerance = (float)$answer-&amp;gt;tolerance + (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;));&lt;br /&gt;
        switch ($answer-&amp;gt;tolerancetype) {&lt;br /&gt;
            case &#039;1&#039;: case &#039;relative&#039;:&lt;br /&gt;
                /// Recalculate the tolerance and fall through&lt;br /&gt;
                /// to the nominal case:&lt;br /&gt;
                $tolerance = $answer-&amp;gt;answer * $tolerance;&lt;br /&gt;
                // Do not fall through to the nominal case because the tiny fraction is a factor of the answer&lt;br /&gt;
                 $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;2&#039;: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                // $answer-&amp;gt;tolerance 0 or something else&lt;br /&gt;
                if ((float)$answer-&amp;gt;tolerance == 0.0  &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance ){&lt;br /&gt;
                    $tolerance = (float) (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) * abs((float)$answer-&amp;gt;answer) ; //tiny fraction&lt;br /&gt;
                } else if ((float)$answer-&amp;gt;tolerance != 0.0 &amp;amp;&amp;amp; abs((float)$answer-&amp;gt;tolerance) &amp;lt; abs((float)$answer-&amp;gt;answer) &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance){&lt;br /&gt;
                    $tolerance = (1+(&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) )* abs((float) $answer-&amp;gt;tolerance) ;//tiny fraction&lt;br /&gt;
               }&lt;br /&gt;
&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;3&#039;: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                $max = $answer-&amp;gt;answer * $quotient;&lt;br /&gt;
                $min = $answer-&amp;gt;answer / $quotient;&lt;br /&gt;
                break;&lt;br /&gt;
            default:&lt;br /&gt;
                error(&amp;quot;Unknown tolerance type $answer-&amp;gt;tolerancetype&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $answer-&amp;gt;min = $min;&lt;br /&gt;
        $answer-&amp;gt;max = $max;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 actual code=&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class qtype_numerical_answer extends question_answer {&lt;br /&gt;
    /** @var float allowable margin of error. */&lt;br /&gt;
    public $tolerance;&lt;br /&gt;
    /** @var integer|string see {@link get_tolerance_interval()} for the meaning of this value. */&lt;br /&gt;
    public $tolerancetype = 2;&lt;br /&gt;
&lt;br /&gt;
    public function __construct($id, $answer, $fraction, $feedback, $feedbackformat, $tolerance) {&lt;br /&gt;
        parent::__construct($id, $answer, $fraction, $feedback, $feedbackformat);&lt;br /&gt;
        $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_tolerance_interval() {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            throw new coding_exception(&#039;Cannot work out tolerance interval for answer *.&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make&lt;br /&gt;
        // the comparison work correctly, otherwise seemingly equal values can&lt;br /&gt;
        // yield false. See MDL-3225.&lt;br /&gt;
        $tolerance = (float) $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;));&lt;br /&gt;
&lt;br /&gt;
        switch ($this-&amp;gt;tolerancetype) {&lt;br /&gt;
            case 1: case &#039;relative&#039;:&lt;br /&gt;
                $range = abs($this-&amp;gt;answer) * $tolerance;&lt;br /&gt;
                return array($this-&amp;gt;answer - $range, $this-&amp;gt;answer + $range);&lt;br /&gt;
&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) *&lt;br /&gt;
                        max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&lt;br /&gt;
            case 3: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                return array($this-&amp;gt;answer / $quotient, $this-&amp;gt;answer * $quotient);&lt;br /&gt;
&lt;br /&gt;
            default:&lt;br /&gt;
                throw new coding_exception(&#039;Unknown tolerance type &#039; . $this-&amp;gt;tolerancetype);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function within_tolerance($value) {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
        list($min, $max) = $this-&amp;gt;get_tolerance_interval();&lt;br /&gt;
        return $min &amp;lt;= $value &amp;amp;&amp;amp; $value &amp;lt;= $max;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 vs 1,9 differences=&lt;br /&gt;
== case relative ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case geometric ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case nominal ==&lt;br /&gt;
The use of &lt;br /&gt;
 pow(10, -1 * ini_get(&#039;precision&#039;)) * max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
The &#039;tiny fraction&#039; part of the tolerance  is not related to the answer when the answer is less than 1. &lt;br /&gt;
&lt;br /&gt;
We should get back to the 1,9 equivalent code first by removing the max function &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The 1,9 code has a special treatment of the answer == 0 .&lt;br /&gt;
&lt;br /&gt;
Should we keep the code ?&lt;br /&gt;
&lt;br /&gt;
=== Answer is 0===&lt;br /&gt;
What is the precision of 0 ?&lt;br /&gt;
It cannot be 0 , it only can be the precision of the digital part of the number i.e.  pow(10, -1 * ini_get(&#039;precision&#039;)).&lt;br /&gt;
As a mather of fact the exponent part of 0 is the same one as 1 so its precision is the same.&lt;br /&gt;
We should not forget that the &amp;quot;turning point&amp;quot; (positive to negative)  of real number exponent value is 1 not 0.&lt;br /&gt;
&lt;br /&gt;
So to get the &amp;quot;tiny number&amp;quot; we should multiply the  pow(10, -1 * ini_get(&#039;precision&#039;)) by $this-&amp;gt;answer except when $this-&amp;gt;answer == 0 when it should be 1.&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 0,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;pow(10, -1 * ini_get(&#039;precision&#039;))=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
&lt;br /&gt;
=== Answer is NOT 0===&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;tiny part&amp;quot; should mostly be calculated as pow(10, -1 * ini_get(&#039;precision&#039;))*$answer&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 2,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;=pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))** $this-&amp;gt;answer ;&lt;br /&gt;
&lt;br /&gt;
=Code flow proposal=&lt;br /&gt;
&lt;br /&gt;
This code reflects the discussion although a more concise version could be built.&lt;br /&gt;
The proposal is somehow different from the 1,9 version as it includes the precision of the tolerance in the range.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    if ($this-&amp;gt;answer == 0.0){&lt;br /&gt;
         if($this-&amp;gt;tolerance == 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)){ // the 0&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         }&lt;br /&gt;
   } else {&lt;br /&gt;
         if($this-&amp;gt;tolerance === 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;answer ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)* abs($this-&amp;gt;answer)){ &lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
         }     &lt;br /&gt;
   }         &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Tim&#039;s idea==&lt;br /&gt;
&lt;br /&gt;
I am wondering whether it works just change &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the 2.0 code to&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max($this-&amp;gt;tolerance, abs($this-&amp;gt;answer), pow(10, -1 * ini_get(&#039;precision&#039;)));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code might be nicer if we define $epsilon = pow(10, -1 * ini_get(&#039;precision&#039;)) at the start of the function.&lt;br /&gt;
&lt;br /&gt;
Finally, I would like to know what tests you propose to add to question/type/numerical/tests/answer_test.php in order to demonstrate that everything is working properly. In particular, what tests would you like to add that will fail with the current code, but which will pass once we have fixed this bug?&lt;br /&gt;
&lt;br /&gt;
--[[User:Tim Hunt|Tim Hunt]] 00:53, 16 August 2012 (WST)&lt;br /&gt;
==Pierre&#039;s comment==&lt;br /&gt;
Thanks for your code expert feedback...&lt;br /&gt;
&lt;br /&gt;
I am using a simple calculated question on 2,0 or a calculated question on 1,9  to test the various combinations with different answers and tolerances.&lt;br /&gt;
&lt;br /&gt;
The range (Min- Max ) is available directly.&lt;br /&gt;
&lt;br /&gt;
At first tests your proposal seems to be working.&lt;br /&gt;
&lt;br /&gt;
I will report here the results of various tests on 1,9, actual 2, your proposal and the more linear code.&lt;br /&gt;
&lt;br /&gt;
This should help us to choose which tests to use.&lt;br /&gt;
&lt;br /&gt;
[[User:Pierre Pichet|Pierre Pichet]] 12:38, 16 August 2012 (WST)&lt;br /&gt;
=Tests results=&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! header 1&lt;br /&gt;
! header 2&lt;br /&gt;
! header 3&lt;br /&gt;
|-&lt;br /&gt;
| row 1, cell 1&lt;br /&gt;
| row 1, cell 2&lt;br /&gt;
| row 1, cell 3&lt;br /&gt;
|-&lt;br /&gt;
| row 2, cell 1&lt;br /&gt;
| row 2, cell 2&lt;br /&gt;
| row 2, cell 3&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34866</id>
		<title>Question Engine 2:Numerical tolerances</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34866"/>
		<updated>2012-08-16T04:39:28Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Analysis of the various tolerances for numerical and calculated question type answer see (MDL-31837)&lt;br /&gt;
&lt;br /&gt;
In grading a numerical response, the (student) numerical value is compared to the answer numerical value.&lt;br /&gt;
&lt;br /&gt;
This comparison allow a tolerance that is associated with the answer and that can be expressed in various ways.&lt;br /&gt;
&lt;br /&gt;
For calculated question answers the tolerance can be of 3 different types: relative, nominal or geometric. &lt;br /&gt;
=Limits of real numbers in PHP=&lt;br /&gt;
&lt;br /&gt;
The following is from http://www.php.net/manual/en/language.types.float.php&lt;br /&gt;
&lt;br /&gt;
The size of a float is platform-dependent, although a maximum of ~1.8e308 with a precision of roughly 14 decimal digits is a common value (the 64 bit IEEE format).&lt;br /&gt;
&lt;br /&gt;
 Warning&lt;br /&gt;
 Floating point precision&lt;br /&gt;
&lt;br /&gt;
Floating point numbers have limited precision. Although it depends on the system, PHP typically uses the IEEE 754 double precision format, which will give a maximum relative error due to rounding in the order of 1.11e-16. Non elementary arithmetic operations may give larger errors, and, of course, error propagation must be considered when several operations are compounded.&lt;br /&gt;
&lt;br /&gt;
Additionally, rational numbers that are exactly representable as floating point numbers in base 10, like 0.1 or 0.7, do not have an exact representation as floating point numbers in base 2, which is used internally, no matter the size of the mantissa. Hence, they cannot be converted into their internal binary counterparts without a small loss of precision. This can lead to confusing results: for example, floor((0.1+0.7)*10) will usually return 7 instead of the expected 8, since the internal representation will be something like 7.9999999999999991118....&lt;br /&gt;
&lt;br /&gt;
So never trust floating number results to the last digit, and do not compare floating point numbers directly for equality. If higher precision is necessary, the arbitrary precision math functions and gmp functions are available.&lt;br /&gt;
&lt;br /&gt;
Since the internal representation is in base 2, 0 and 1 will have the same exponent so the precision ( i.e. init_get(&#039;precision&#039;) should have the same value.?&lt;br /&gt;
&lt;br /&gt;
....&lt;br /&gt;
=1,9 version=&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
function get_tolerance_interval(&amp;amp;$answer) {&lt;br /&gt;
        // No tolerance&lt;br /&gt;
        if (empty($answer-&amp;gt;tolerance)) {&lt;br /&gt;
            $answer-&amp;gt;tolerance = 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Calculate the interval of correct responses (min/max)&lt;br /&gt;
        if (!isset($answer-&amp;gt;tolerancetype)) {&lt;br /&gt;
            $answer-&amp;gt;tolerancetype = 2; // nominal&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make the&lt;br /&gt;
        // comparison work correctly. Otherwise seemingly equal values can yield&lt;br /&gt;
        // false. (fixes bug #3225)&lt;br /&gt;
        $tolerance = (float)$answer-&amp;gt;tolerance + (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;));&lt;br /&gt;
        switch ($answer-&amp;gt;tolerancetype) {&lt;br /&gt;
            case &#039;1&#039;: case &#039;relative&#039;:&lt;br /&gt;
                /// Recalculate the tolerance and fall through&lt;br /&gt;
                /// to the nominal case:&lt;br /&gt;
                $tolerance = $answer-&amp;gt;answer * $tolerance;&lt;br /&gt;
                // Do not fall through to the nominal case because the tiny fraction is a factor of the answer&lt;br /&gt;
                 $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;2&#039;: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                // $answer-&amp;gt;tolerance 0 or something else&lt;br /&gt;
                if ((float)$answer-&amp;gt;tolerance == 0.0  &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance ){&lt;br /&gt;
                    $tolerance = (float) (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) * abs((float)$answer-&amp;gt;answer) ; //tiny fraction&lt;br /&gt;
                } else if ((float)$answer-&amp;gt;tolerance != 0.0 &amp;amp;&amp;amp; abs((float)$answer-&amp;gt;tolerance) &amp;lt; abs((float)$answer-&amp;gt;answer) &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance){&lt;br /&gt;
                    $tolerance = (1+(&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) )* abs((float) $answer-&amp;gt;tolerance) ;//tiny fraction&lt;br /&gt;
               }&lt;br /&gt;
&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;3&#039;: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                $max = $answer-&amp;gt;answer * $quotient;&lt;br /&gt;
                $min = $answer-&amp;gt;answer / $quotient;&lt;br /&gt;
                break;&lt;br /&gt;
            default:&lt;br /&gt;
                error(&amp;quot;Unknown tolerance type $answer-&amp;gt;tolerancetype&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $answer-&amp;gt;min = $min;&lt;br /&gt;
        $answer-&amp;gt;max = $max;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 actual code=&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class qtype_numerical_answer extends question_answer {&lt;br /&gt;
    /** @var float allowable margin of error. */&lt;br /&gt;
    public $tolerance;&lt;br /&gt;
    /** @var integer|string see {@link get_tolerance_interval()} for the meaning of this value. */&lt;br /&gt;
    public $tolerancetype = 2;&lt;br /&gt;
&lt;br /&gt;
    public function __construct($id, $answer, $fraction, $feedback, $feedbackformat, $tolerance) {&lt;br /&gt;
        parent::__construct($id, $answer, $fraction, $feedback, $feedbackformat);&lt;br /&gt;
        $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_tolerance_interval() {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            throw new coding_exception(&#039;Cannot work out tolerance interval for answer *.&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make&lt;br /&gt;
        // the comparison work correctly, otherwise seemingly equal values can&lt;br /&gt;
        // yield false. See MDL-3225.&lt;br /&gt;
        $tolerance = (float) $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;));&lt;br /&gt;
&lt;br /&gt;
        switch ($this-&amp;gt;tolerancetype) {&lt;br /&gt;
            case 1: case &#039;relative&#039;:&lt;br /&gt;
                $range = abs($this-&amp;gt;answer) * $tolerance;&lt;br /&gt;
                return array($this-&amp;gt;answer - $range, $this-&amp;gt;answer + $range);&lt;br /&gt;
&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) *&lt;br /&gt;
                        max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&lt;br /&gt;
            case 3: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                return array($this-&amp;gt;answer / $quotient, $this-&amp;gt;answer * $quotient);&lt;br /&gt;
&lt;br /&gt;
            default:&lt;br /&gt;
                throw new coding_exception(&#039;Unknown tolerance type &#039; . $this-&amp;gt;tolerancetype);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function within_tolerance($value) {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
        list($min, $max) = $this-&amp;gt;get_tolerance_interval();&lt;br /&gt;
        return $min &amp;lt;= $value &amp;amp;&amp;amp; $value &amp;lt;= $max;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 vs 1,9 differences=&lt;br /&gt;
== case relative ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case geometric ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case nominal ==&lt;br /&gt;
The use of &lt;br /&gt;
 pow(10, -1 * ini_get(&#039;precision&#039;)) * max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
The &#039;tiny fraction&#039; part of the tolerance  is not related to the answer when the answer is less than 1. &lt;br /&gt;
&lt;br /&gt;
We should get back to the 1,9 equivalent code first by removing the max function &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The 1,9 code has a special treatment of the answer == 0 .&lt;br /&gt;
&lt;br /&gt;
Should we keep the code ?&lt;br /&gt;
&lt;br /&gt;
=== Answer is 0===&lt;br /&gt;
What is the precision of 0 ?&lt;br /&gt;
It cannot be 0 , it only can be the precision of the digital part of the number i.e.  pow(10, -1 * ini_get(&#039;precision&#039;)).&lt;br /&gt;
As a mather of fact the exponent part of 0 is the same one as 1 so its precision is the same.&lt;br /&gt;
We should not forget that the &amp;quot;turning point&amp;quot; (positive to negative)  of real number exponent value is 1 not 0.&lt;br /&gt;
&lt;br /&gt;
So to get the &amp;quot;tiny number&amp;quot; we should multiply the  pow(10, -1 * ini_get(&#039;precision&#039;)) by $this-&amp;gt;answer except when $this-&amp;gt;answer == 0 when it should be 1.&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 0,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;pow(10, -1 * ini_get(&#039;precision&#039;))=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
&lt;br /&gt;
=== Answer is NOT 0===&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;tiny part&amp;quot; should mostly be calculated as pow(10, -1 * ini_get(&#039;precision&#039;))*$answer&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 2,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;=pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))** $this-&amp;gt;answer ;&lt;br /&gt;
&lt;br /&gt;
=Code flow proposal=&lt;br /&gt;
&lt;br /&gt;
This code reflects the discussion although a more concise version could be built.&lt;br /&gt;
The proposal is somehow different from the 1,9 version as it includes the precision of the tolerance in the range.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    if ($this-&amp;gt;answer == 0.0){&lt;br /&gt;
         if($this-&amp;gt;tolerance == 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)){ // the 0&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         }&lt;br /&gt;
   } else {&lt;br /&gt;
         if($this-&amp;gt;tolerance === 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;answer ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)* abs($this-&amp;gt;answer)){ &lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
         }     &lt;br /&gt;
   }         &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Tim&#039;s idea==&lt;br /&gt;
&lt;br /&gt;
I am wondering whether it works just change &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the 2.0 code to&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max($this-&amp;gt;tolerance, abs($this-&amp;gt;answer), pow(10, -1 * ini_get(&#039;precision&#039;)));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code might be nicer if we define $epsilon = pow(10, -1 * ini_get(&#039;precision&#039;)) at the start of the function.&lt;br /&gt;
&lt;br /&gt;
Finally, I would like to know what tests you propose to add to question/type/numerical/tests/answer_test.php in order to demonstrate that everything is working properly. In particular, what tests would you like to add that will fail with the current code, but which will pass once we have fixed this bug?&lt;br /&gt;
&lt;br /&gt;
--[[User:Tim Hunt|Tim Hunt]] 00:53, 16 August 2012 (WST)&lt;br /&gt;
==Pierre&#039;s comment==&lt;br /&gt;
Thanks for your code expert feedback...&lt;br /&gt;
&lt;br /&gt;
I am using a simple calculated question on 2,0 or a calculated question on 1,9  to test the various combinations with different answers and tolerances.&lt;br /&gt;
&lt;br /&gt;
The range (Min- Max ) is available directly.&lt;br /&gt;
&lt;br /&gt;
At first tests your proposal seems to be working.&lt;br /&gt;
&lt;br /&gt;
I will report here the results of various tests on 1,9, actual 2, your proposal and the more linear code.&lt;br /&gt;
&lt;br /&gt;
This should help us to choose which tests to use.&lt;br /&gt;
&lt;br /&gt;
[[User:Pierre Pichet|Pierre Pichet]] 12:38, 16 August 2012 (WST)&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34865</id>
		<title>Question Engine 2:Numerical tolerances</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34865"/>
		<updated>2012-08-16T04:38:05Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Analysis of the various tolerances for numerical and calculated question type answer see (MDL-31837)&lt;br /&gt;
&lt;br /&gt;
This is a first version [[User:Pierre Pichet|Pierre Pichet]] 20:27, 15 August 2012 (WST)&lt;br /&gt;
&lt;br /&gt;
In grading a numerical response, the (student) numerical value is compared to the answer numerical value.&lt;br /&gt;
&lt;br /&gt;
This comparison allow a tolerance that is associated with the answer and that can be expressed in various ways.&lt;br /&gt;
&lt;br /&gt;
For calculated question answers the tolerance can be of 3 different types: relative, nominal or geometric. &lt;br /&gt;
=Limits of real numbers in PHP=&lt;br /&gt;
&lt;br /&gt;
The following is from http://www.php.net/manual/en/language.types.float.php&lt;br /&gt;
&lt;br /&gt;
The size of a float is platform-dependent, although a maximum of ~1.8e308 with a precision of roughly 14 decimal digits is a common value (the 64 bit IEEE format).&lt;br /&gt;
&lt;br /&gt;
 Warning&lt;br /&gt;
 Floating point precision&lt;br /&gt;
&lt;br /&gt;
Floating point numbers have limited precision. Although it depends on the system, PHP typically uses the IEEE 754 double precision format, which will give a maximum relative error due to rounding in the order of 1.11e-16. Non elementary arithmetic operations may give larger errors, and, of course, error propagation must be considered when several operations are compounded.&lt;br /&gt;
&lt;br /&gt;
Additionally, rational numbers that are exactly representable as floating point numbers in base 10, like 0.1 or 0.7, do not have an exact representation as floating point numbers in base 2, which is used internally, no matter the size of the mantissa. Hence, they cannot be converted into their internal binary counterparts without a small loss of precision. This can lead to confusing results: for example, floor((0.1+0.7)*10) will usually return 7 instead of the expected 8, since the internal representation will be something like 7.9999999999999991118....&lt;br /&gt;
&lt;br /&gt;
So never trust floating number results to the last digit, and do not compare floating point numbers directly for equality. If higher precision is necessary, the arbitrary precision math functions and gmp functions are available.&lt;br /&gt;
&lt;br /&gt;
Since the internal representation is in base 2, 0 and 1 will have the same exponent so the precision ( i.e. init_get(&#039;precision&#039;) should have the same value.?&lt;br /&gt;
&lt;br /&gt;
....&lt;br /&gt;
=1,9 version=&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
function get_tolerance_interval(&amp;amp;$answer) {&lt;br /&gt;
        // No tolerance&lt;br /&gt;
        if (empty($answer-&amp;gt;tolerance)) {&lt;br /&gt;
            $answer-&amp;gt;tolerance = 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Calculate the interval of correct responses (min/max)&lt;br /&gt;
        if (!isset($answer-&amp;gt;tolerancetype)) {&lt;br /&gt;
            $answer-&amp;gt;tolerancetype = 2; // nominal&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make the&lt;br /&gt;
        // comparison work correctly. Otherwise seemingly equal values can yield&lt;br /&gt;
        // false. (fixes bug #3225)&lt;br /&gt;
        $tolerance = (float)$answer-&amp;gt;tolerance + (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;));&lt;br /&gt;
        switch ($answer-&amp;gt;tolerancetype) {&lt;br /&gt;
            case &#039;1&#039;: case &#039;relative&#039;:&lt;br /&gt;
                /// Recalculate the tolerance and fall through&lt;br /&gt;
                /// to the nominal case:&lt;br /&gt;
                $tolerance = $answer-&amp;gt;answer * $tolerance;&lt;br /&gt;
                // Do not fall through to the nominal case because the tiny fraction is a factor of the answer&lt;br /&gt;
                 $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;2&#039;: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                // $answer-&amp;gt;tolerance 0 or something else&lt;br /&gt;
                if ((float)$answer-&amp;gt;tolerance == 0.0  &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance ){&lt;br /&gt;
                    $tolerance = (float) (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) * abs((float)$answer-&amp;gt;answer) ; //tiny fraction&lt;br /&gt;
                } else if ((float)$answer-&amp;gt;tolerance != 0.0 &amp;amp;&amp;amp; abs((float)$answer-&amp;gt;tolerance) &amp;lt; abs((float)$answer-&amp;gt;answer) &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance){&lt;br /&gt;
                    $tolerance = (1+(&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) )* abs((float) $answer-&amp;gt;tolerance) ;//tiny fraction&lt;br /&gt;
               }&lt;br /&gt;
&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;3&#039;: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                $max = $answer-&amp;gt;answer * $quotient;&lt;br /&gt;
                $min = $answer-&amp;gt;answer / $quotient;&lt;br /&gt;
                break;&lt;br /&gt;
            default:&lt;br /&gt;
                error(&amp;quot;Unknown tolerance type $answer-&amp;gt;tolerancetype&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $answer-&amp;gt;min = $min;&lt;br /&gt;
        $answer-&amp;gt;max = $max;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 actual code=&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class qtype_numerical_answer extends question_answer {&lt;br /&gt;
    /** @var float allowable margin of error. */&lt;br /&gt;
    public $tolerance;&lt;br /&gt;
    /** @var integer|string see {@link get_tolerance_interval()} for the meaning of this value. */&lt;br /&gt;
    public $tolerancetype = 2;&lt;br /&gt;
&lt;br /&gt;
    public function __construct($id, $answer, $fraction, $feedback, $feedbackformat, $tolerance) {&lt;br /&gt;
        parent::__construct($id, $answer, $fraction, $feedback, $feedbackformat);&lt;br /&gt;
        $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_tolerance_interval() {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            throw new coding_exception(&#039;Cannot work out tolerance interval for answer *.&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make&lt;br /&gt;
        // the comparison work correctly, otherwise seemingly equal values can&lt;br /&gt;
        // yield false. See MDL-3225.&lt;br /&gt;
        $tolerance = (float) $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;));&lt;br /&gt;
&lt;br /&gt;
        switch ($this-&amp;gt;tolerancetype) {&lt;br /&gt;
            case 1: case &#039;relative&#039;:&lt;br /&gt;
                $range = abs($this-&amp;gt;answer) * $tolerance;&lt;br /&gt;
                return array($this-&amp;gt;answer - $range, $this-&amp;gt;answer + $range);&lt;br /&gt;
&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) *&lt;br /&gt;
                        max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&lt;br /&gt;
            case 3: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                return array($this-&amp;gt;answer / $quotient, $this-&amp;gt;answer * $quotient);&lt;br /&gt;
&lt;br /&gt;
            default:&lt;br /&gt;
                throw new coding_exception(&#039;Unknown tolerance type &#039; . $this-&amp;gt;tolerancetype);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function within_tolerance($value) {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
        list($min, $max) = $this-&amp;gt;get_tolerance_interval();&lt;br /&gt;
        return $min &amp;lt;= $value &amp;amp;&amp;amp; $value &amp;lt;= $max;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 vs 1,9 differences=&lt;br /&gt;
== case relative ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case geometric ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case nominal ==&lt;br /&gt;
The use of &lt;br /&gt;
 pow(10, -1 * ini_get(&#039;precision&#039;)) * max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
The &#039;tiny fraction&#039; part of the tolerance  is not related to the answer when the answer is less than 1. &lt;br /&gt;
&lt;br /&gt;
We should get back to the 1,9 equivalent code first by removing the max function &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The 1,9 code has a special treatment of the answer == 0 .&lt;br /&gt;
&lt;br /&gt;
Should we keep the code ?&lt;br /&gt;
&lt;br /&gt;
=== Answer is 0===&lt;br /&gt;
What is the precision of 0 ?&lt;br /&gt;
It cannot be 0 , it only can be the precision of the digital part of the number i.e.  pow(10, -1 * ini_get(&#039;precision&#039;)).&lt;br /&gt;
As a mather of fact the exponent part of 0 is the same one as 1 so its precision is the same.&lt;br /&gt;
We should not forget that the &amp;quot;turning point&amp;quot; (positive to negative)  of real number exponent value is 1 not 0.&lt;br /&gt;
&lt;br /&gt;
So to get the &amp;quot;tiny number&amp;quot; we should multiply the  pow(10, -1 * ini_get(&#039;precision&#039;)) by $this-&amp;gt;answer except when $this-&amp;gt;answer == 0 when it should be 1.&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 0,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;pow(10, -1 * ini_get(&#039;precision&#039;))=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
&lt;br /&gt;
=== Answer is NOT 0===&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;tiny part&amp;quot; should mostly be calculated as pow(10, -1 * ini_get(&#039;precision&#039;))*$answer&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 2,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;=pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))** $this-&amp;gt;answer ;&lt;br /&gt;
&lt;br /&gt;
=Code flow proposal=&lt;br /&gt;
&lt;br /&gt;
This code reflects the discussion although a more concise version could be built.&lt;br /&gt;
The proposal is somehow different from the 1,9 version as it includes the precision of the tolerance in the range.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    if ($this-&amp;gt;answer == 0.0){&lt;br /&gt;
         if($this-&amp;gt;tolerance == 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)){ // the 0&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         }&lt;br /&gt;
   } else {&lt;br /&gt;
         if($this-&amp;gt;tolerance === 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;answer ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)* abs($this-&amp;gt;answer)){ &lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
         }     &lt;br /&gt;
   }         &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Tim&#039;s idea==&lt;br /&gt;
&lt;br /&gt;
I am wondering whether it works just change &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the 2.0 code to&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max($this-&amp;gt;tolerance, abs($this-&amp;gt;answer), pow(10, -1 * ini_get(&#039;precision&#039;)));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code might be nicer if we define $epsilon = pow(10, -1 * ini_get(&#039;precision&#039;)) at the start of the function.&lt;br /&gt;
&lt;br /&gt;
Finally, I would like to know what tests you propose to add to question/type/numerical/tests/answer_test.php in order to demonstrate that everything is working properly. In particular, what tests would you like to add that will fail with the current code, but which will pass once we have fixed this bug?&lt;br /&gt;
&lt;br /&gt;
--[[User:Tim Hunt|Tim Hunt]] 00:53, 16 August 2012 (WST)&lt;br /&gt;
==Pierre&#039;s comment==&lt;br /&gt;
Thanks for your code expert feedback...&lt;br /&gt;
&lt;br /&gt;
I am using a simple calculated question on 2,0 or a calculated question on 1,9  to test the various combinations with different answers and tolerances.&lt;br /&gt;
&lt;br /&gt;
The range (Min- Max ) is available directly.&lt;br /&gt;
&lt;br /&gt;
At first tests your proposal seems to be working.&lt;br /&gt;
&lt;br /&gt;
I will report here the results of various tests on 1,9, actual 2, your proposal and the more linear code.&lt;br /&gt;
&lt;br /&gt;
This should help us to choose which tests to use.&lt;br /&gt;
&lt;br /&gt;
[[User:Pierre Pichet|Pierre Pichet]] 12:38, 16 August 2012 (WST)&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34860</id>
		<title>Question Engine 2:Numerical tolerances</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34860"/>
		<updated>2012-08-15T23:43:58Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: /* Pierre&amp;#039; comment */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Analysis of the various tolerances for numerical and calculated question type answer see (MDL-31837)&lt;br /&gt;
&lt;br /&gt;
This is a first version [[User:Pierre Pichet|Pierre Pichet]] 20:27, 15 August 2012 (WST)&lt;br /&gt;
&lt;br /&gt;
In grading a numerical response, the (student) numerical value is compared to the answer numerical value.&lt;br /&gt;
&lt;br /&gt;
This comparison allow a tolerance that is associated with the answer and that can be expressed in various ways.&lt;br /&gt;
&lt;br /&gt;
For calculated question answers the tolerance can be of 3 different types: relative, nominal or geometric. &lt;br /&gt;
=Limits of real numbers in PHP=&lt;br /&gt;
&lt;br /&gt;
The following is from http://www.php.net/manual/en/language.types.float.php&lt;br /&gt;
&lt;br /&gt;
The size of a float is platform-dependent, although a maximum of ~1.8e308 with a precision of roughly 14 decimal digits is a common value (the 64 bit IEEE format).&lt;br /&gt;
&lt;br /&gt;
 Warning&lt;br /&gt;
 Floating point precision&lt;br /&gt;
&lt;br /&gt;
Floating point numbers have limited precision. Although it depends on the system, PHP typically uses the IEEE 754 double precision format, which will give a maximum relative error due to rounding in the order of 1.11e-16. Non elementary arithmetic operations may give larger errors, and, of course, error propagation must be considered when several operations are compounded.&lt;br /&gt;
&lt;br /&gt;
Additionally, rational numbers that are exactly representable as floating point numbers in base 10, like 0.1 or 0.7, do not have an exact representation as floating point numbers in base 2, which is used internally, no matter the size of the mantissa. Hence, they cannot be converted into their internal binary counterparts without a small loss of precision. This can lead to confusing results: for example, floor((0.1+0.7)*10) will usually return 7 instead of the expected 8, since the internal representation will be something like 7.9999999999999991118....&lt;br /&gt;
&lt;br /&gt;
So never trust floating number results to the last digit, and do not compare floating point numbers directly for equality. If higher precision is necessary, the arbitrary precision math functions and gmp functions are available.&lt;br /&gt;
&lt;br /&gt;
Since the internal representation is in base 2, 0 and 1 will have the same exponent so the precision ( i.e. init_get(&#039;precision&#039;) should have the same value.?&lt;br /&gt;
&lt;br /&gt;
....&lt;br /&gt;
=1,9 version=&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
function get_tolerance_interval(&amp;amp;$answer) {&lt;br /&gt;
        // No tolerance&lt;br /&gt;
        if (empty($answer-&amp;gt;tolerance)) {&lt;br /&gt;
            $answer-&amp;gt;tolerance = 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Calculate the interval of correct responses (min/max)&lt;br /&gt;
        if (!isset($answer-&amp;gt;tolerancetype)) {&lt;br /&gt;
            $answer-&amp;gt;tolerancetype = 2; // nominal&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make the&lt;br /&gt;
        // comparison work correctly. Otherwise seemingly equal values can yield&lt;br /&gt;
        // false. (fixes bug #3225)&lt;br /&gt;
        $tolerance = (float)$answer-&amp;gt;tolerance + (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;));&lt;br /&gt;
        switch ($answer-&amp;gt;tolerancetype) {&lt;br /&gt;
            case &#039;1&#039;: case &#039;relative&#039;:&lt;br /&gt;
                /// Recalculate the tolerance and fall through&lt;br /&gt;
                /// to the nominal case:&lt;br /&gt;
                $tolerance = $answer-&amp;gt;answer * $tolerance;&lt;br /&gt;
                // Do not fall through to the nominal case because the tiny fraction is a factor of the answer&lt;br /&gt;
                 $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;2&#039;: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                // $answer-&amp;gt;tolerance 0 or something else&lt;br /&gt;
                if ((float)$answer-&amp;gt;tolerance == 0.0  &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance ){&lt;br /&gt;
                    $tolerance = (float) (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) * abs((float)$answer-&amp;gt;answer) ; //tiny fraction&lt;br /&gt;
                } else if ((float)$answer-&amp;gt;tolerance != 0.0 &amp;amp;&amp;amp; abs((float)$answer-&amp;gt;tolerance) &amp;lt; abs((float)$answer-&amp;gt;answer) &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance){&lt;br /&gt;
                    $tolerance = (1+(&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) )* abs((float) $answer-&amp;gt;tolerance) ;//tiny fraction&lt;br /&gt;
               }&lt;br /&gt;
&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;3&#039;: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                $max = $answer-&amp;gt;answer * $quotient;&lt;br /&gt;
                $min = $answer-&amp;gt;answer / $quotient;&lt;br /&gt;
                break;&lt;br /&gt;
            default:&lt;br /&gt;
                error(&amp;quot;Unknown tolerance type $answer-&amp;gt;tolerancetype&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $answer-&amp;gt;min = $min;&lt;br /&gt;
        $answer-&amp;gt;max = $max;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 actual code=&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class qtype_numerical_answer extends question_answer {&lt;br /&gt;
    /** @var float allowable margin of error. */&lt;br /&gt;
    public $tolerance;&lt;br /&gt;
    /** @var integer|string see {@link get_tolerance_interval()} for the meaning of this value. */&lt;br /&gt;
    public $tolerancetype = 2;&lt;br /&gt;
&lt;br /&gt;
    public function __construct($id, $answer, $fraction, $feedback, $feedbackformat, $tolerance) {&lt;br /&gt;
        parent::__construct($id, $answer, $fraction, $feedback, $feedbackformat);&lt;br /&gt;
        $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_tolerance_interval() {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            throw new coding_exception(&#039;Cannot work out tolerance interval for answer *.&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make&lt;br /&gt;
        // the comparison work correctly, otherwise seemingly equal values can&lt;br /&gt;
        // yield false. See MDL-3225.&lt;br /&gt;
        $tolerance = (float) $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;));&lt;br /&gt;
&lt;br /&gt;
        switch ($this-&amp;gt;tolerancetype) {&lt;br /&gt;
            case 1: case &#039;relative&#039;:&lt;br /&gt;
                $range = abs($this-&amp;gt;answer) * $tolerance;&lt;br /&gt;
                return array($this-&amp;gt;answer - $range, $this-&amp;gt;answer + $range);&lt;br /&gt;
&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) *&lt;br /&gt;
                        max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&lt;br /&gt;
            case 3: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                return array($this-&amp;gt;answer / $quotient, $this-&amp;gt;answer * $quotient);&lt;br /&gt;
&lt;br /&gt;
            default:&lt;br /&gt;
                throw new coding_exception(&#039;Unknown tolerance type &#039; . $this-&amp;gt;tolerancetype);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function within_tolerance($value) {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
        list($min, $max) = $this-&amp;gt;get_tolerance_interval();&lt;br /&gt;
        return $min &amp;lt;= $value &amp;amp;&amp;amp; $value &amp;lt;= $max;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 vs 1,9 differences=&lt;br /&gt;
== case relative ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case geometric ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case nominal ==&lt;br /&gt;
The use of &lt;br /&gt;
 pow(10, -1 * ini_get(&#039;precision&#039;)) * max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
The &#039;tiny fraction&#039; part of the tolerance  is not related to the answer when the answer is less than 1. &lt;br /&gt;
&lt;br /&gt;
We should get back to the 1,9 equivalent code first by removing the max function &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The 1,9 code has a special treatment of the answer == 0 .&lt;br /&gt;
&lt;br /&gt;
Should we keep the code ?&lt;br /&gt;
&lt;br /&gt;
=== Answer is 0===&lt;br /&gt;
What is the precision of 0 ?&lt;br /&gt;
It cannot be 0 , it only can be the precision of the digital part of the number i.e.  pow(10, -1 * ini_get(&#039;precision&#039;)).&lt;br /&gt;
As a mather of fact the exponent part of 0 is the same one as 1 so its precision is the same.&lt;br /&gt;
We should not forget that the &amp;quot;turning point&amp;quot; (positive to negative)  of real number exponent value is 1 not 0.&lt;br /&gt;
&lt;br /&gt;
So to get the &amp;quot;tiny number&amp;quot; we should multiply the  pow(10, -1 * ini_get(&#039;precision&#039;)) by $this-&amp;gt;answer except when $this-&amp;gt;answer == 0 when it should be 1.&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 0,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;pow(10, -1 * ini_get(&#039;precision&#039;))=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
&lt;br /&gt;
=== Answer is NOT 0===&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;tiny part&amp;quot; should mostly be calculated as pow(10, -1 * ini_get(&#039;precision&#039;))*$answer&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 2,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;=pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))** $this-&amp;gt;answer ;&lt;br /&gt;
&lt;br /&gt;
=Code flow proposal=&lt;br /&gt;
&lt;br /&gt;
This code reflects the discussion although a more concise version could be built.&lt;br /&gt;
The proposal is somehow different from the 1,9 version as it includes the precision of the tolerance in the range.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    if ($this-&amp;gt;answer == 0.0){&lt;br /&gt;
         if($this-&amp;gt;tolerance == 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)){ // the 0&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         }&lt;br /&gt;
   } else {&lt;br /&gt;
         if($this-&amp;gt;tolerance === 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;answer ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)* abs($this-&amp;gt;answer)){ &lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
         }     &lt;br /&gt;
   }         &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Tim&#039;s idea==&lt;br /&gt;
&lt;br /&gt;
I am wondering whether it works just change &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the 2.0 code to&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max($this-&amp;gt;tolerance, abs($this-&amp;gt;answer), pow(10, -1 * ini_get(&#039;precision&#039;)));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code might be nicer if we define $epsilon = pow(10, -1 * ini_get(&#039;precision&#039;)) at the start of the function.&lt;br /&gt;
&lt;br /&gt;
Finally, I would like to know what tests you propose to add to question/type/numerical/tests/answer_test.php in order to demonstrate that everything is working properly. In particular, what tests would you like to add that will fail with the current code, but which will pass once we have fixed this bug?&lt;br /&gt;
&lt;br /&gt;
--[[User:Tim Hunt|Tim Hunt]] 00:53, 16 August 2012 (WST)&lt;br /&gt;
==Pierre&#039;s comment==&lt;br /&gt;
Thanks for your code expert feedback...&lt;br /&gt;
&lt;br /&gt;
I am using a simple calculated question on 2,0 or a calculated question on 1,9  to test the various combinations with different answers and tolerances.&lt;br /&gt;
&lt;br /&gt;
The range (Min- Max ) is available directly.&lt;br /&gt;
&lt;br /&gt;
At first tests your proposal seems to be working.&lt;br /&gt;
&lt;br /&gt;
[[User:Pierre Pichet|Pierre Pichet]] 07:43, 16 August 2012 (WST)&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34859</id>
		<title>Question Engine 2:Numerical tolerances</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34859"/>
		<updated>2012-08-15T23:43:16Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: /* Tim&amp;#039;s idea */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Analysis of the various tolerances for numerical and calculated question type answer see (MDL-31837)&lt;br /&gt;
&lt;br /&gt;
This is a first version [[User:Pierre Pichet|Pierre Pichet]] 20:27, 15 August 2012 (WST)&lt;br /&gt;
&lt;br /&gt;
In grading a numerical response, the (student) numerical value is compared to the answer numerical value.&lt;br /&gt;
&lt;br /&gt;
This comparison allow a tolerance that is associated with the answer and that can be expressed in various ways.&lt;br /&gt;
&lt;br /&gt;
For calculated question answers the tolerance can be of 3 different types: relative, nominal or geometric. &lt;br /&gt;
=Limits of real numbers in PHP=&lt;br /&gt;
&lt;br /&gt;
The following is from http://www.php.net/manual/en/language.types.float.php&lt;br /&gt;
&lt;br /&gt;
The size of a float is platform-dependent, although a maximum of ~1.8e308 with a precision of roughly 14 decimal digits is a common value (the 64 bit IEEE format).&lt;br /&gt;
&lt;br /&gt;
 Warning&lt;br /&gt;
 Floating point precision&lt;br /&gt;
&lt;br /&gt;
Floating point numbers have limited precision. Although it depends on the system, PHP typically uses the IEEE 754 double precision format, which will give a maximum relative error due to rounding in the order of 1.11e-16. Non elementary arithmetic operations may give larger errors, and, of course, error propagation must be considered when several operations are compounded.&lt;br /&gt;
&lt;br /&gt;
Additionally, rational numbers that are exactly representable as floating point numbers in base 10, like 0.1 or 0.7, do not have an exact representation as floating point numbers in base 2, which is used internally, no matter the size of the mantissa. Hence, they cannot be converted into their internal binary counterparts without a small loss of precision. This can lead to confusing results: for example, floor((0.1+0.7)*10) will usually return 7 instead of the expected 8, since the internal representation will be something like 7.9999999999999991118....&lt;br /&gt;
&lt;br /&gt;
So never trust floating number results to the last digit, and do not compare floating point numbers directly for equality. If higher precision is necessary, the arbitrary precision math functions and gmp functions are available.&lt;br /&gt;
&lt;br /&gt;
Since the internal representation is in base 2, 0 and 1 will have the same exponent so the precision ( i.e. init_get(&#039;precision&#039;) should have the same value.?&lt;br /&gt;
&lt;br /&gt;
....&lt;br /&gt;
=1,9 version=&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
function get_tolerance_interval(&amp;amp;$answer) {&lt;br /&gt;
        // No tolerance&lt;br /&gt;
        if (empty($answer-&amp;gt;tolerance)) {&lt;br /&gt;
            $answer-&amp;gt;tolerance = 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Calculate the interval of correct responses (min/max)&lt;br /&gt;
        if (!isset($answer-&amp;gt;tolerancetype)) {&lt;br /&gt;
            $answer-&amp;gt;tolerancetype = 2; // nominal&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make the&lt;br /&gt;
        // comparison work correctly. Otherwise seemingly equal values can yield&lt;br /&gt;
        // false. (fixes bug #3225)&lt;br /&gt;
        $tolerance = (float)$answer-&amp;gt;tolerance + (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;));&lt;br /&gt;
        switch ($answer-&amp;gt;tolerancetype) {&lt;br /&gt;
            case &#039;1&#039;: case &#039;relative&#039;:&lt;br /&gt;
                /// Recalculate the tolerance and fall through&lt;br /&gt;
                /// to the nominal case:&lt;br /&gt;
                $tolerance = $answer-&amp;gt;answer * $tolerance;&lt;br /&gt;
                // Do not fall through to the nominal case because the tiny fraction is a factor of the answer&lt;br /&gt;
                 $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;2&#039;: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                // $answer-&amp;gt;tolerance 0 or something else&lt;br /&gt;
                if ((float)$answer-&amp;gt;tolerance == 0.0  &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance ){&lt;br /&gt;
                    $tolerance = (float) (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) * abs((float)$answer-&amp;gt;answer) ; //tiny fraction&lt;br /&gt;
                } else if ((float)$answer-&amp;gt;tolerance != 0.0 &amp;amp;&amp;amp; abs((float)$answer-&amp;gt;tolerance) &amp;lt; abs((float)$answer-&amp;gt;answer) &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance){&lt;br /&gt;
                    $tolerance = (1+(&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) )* abs((float) $answer-&amp;gt;tolerance) ;//tiny fraction&lt;br /&gt;
               }&lt;br /&gt;
&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;3&#039;: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                $max = $answer-&amp;gt;answer * $quotient;&lt;br /&gt;
                $min = $answer-&amp;gt;answer / $quotient;&lt;br /&gt;
                break;&lt;br /&gt;
            default:&lt;br /&gt;
                error(&amp;quot;Unknown tolerance type $answer-&amp;gt;tolerancetype&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $answer-&amp;gt;min = $min;&lt;br /&gt;
        $answer-&amp;gt;max = $max;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 actual code=&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class qtype_numerical_answer extends question_answer {&lt;br /&gt;
    /** @var float allowable margin of error. */&lt;br /&gt;
    public $tolerance;&lt;br /&gt;
    /** @var integer|string see {@link get_tolerance_interval()} for the meaning of this value. */&lt;br /&gt;
    public $tolerancetype = 2;&lt;br /&gt;
&lt;br /&gt;
    public function __construct($id, $answer, $fraction, $feedback, $feedbackformat, $tolerance) {&lt;br /&gt;
        parent::__construct($id, $answer, $fraction, $feedback, $feedbackformat);&lt;br /&gt;
        $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_tolerance_interval() {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            throw new coding_exception(&#039;Cannot work out tolerance interval for answer *.&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make&lt;br /&gt;
        // the comparison work correctly, otherwise seemingly equal values can&lt;br /&gt;
        // yield false. See MDL-3225.&lt;br /&gt;
        $tolerance = (float) $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;));&lt;br /&gt;
&lt;br /&gt;
        switch ($this-&amp;gt;tolerancetype) {&lt;br /&gt;
            case 1: case &#039;relative&#039;:&lt;br /&gt;
                $range = abs($this-&amp;gt;answer) * $tolerance;&lt;br /&gt;
                return array($this-&amp;gt;answer - $range, $this-&amp;gt;answer + $range);&lt;br /&gt;
&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) *&lt;br /&gt;
                        max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&lt;br /&gt;
            case 3: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                return array($this-&amp;gt;answer / $quotient, $this-&amp;gt;answer * $quotient);&lt;br /&gt;
&lt;br /&gt;
            default:&lt;br /&gt;
                throw new coding_exception(&#039;Unknown tolerance type &#039; . $this-&amp;gt;tolerancetype);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function within_tolerance($value) {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
        list($min, $max) = $this-&amp;gt;get_tolerance_interval();&lt;br /&gt;
        return $min &amp;lt;= $value &amp;amp;&amp;amp; $value &amp;lt;= $max;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 vs 1,9 differences=&lt;br /&gt;
== case relative ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case geometric ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case nominal ==&lt;br /&gt;
The use of &lt;br /&gt;
 pow(10, -1 * ini_get(&#039;precision&#039;)) * max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
The &#039;tiny fraction&#039; part of the tolerance  is not related to the answer when the answer is less than 1. &lt;br /&gt;
&lt;br /&gt;
We should get back to the 1,9 equivalent code first by removing the max function &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The 1,9 code has a special treatment of the answer == 0 .&lt;br /&gt;
&lt;br /&gt;
Should we keep the code ?&lt;br /&gt;
&lt;br /&gt;
=== Answer is 0===&lt;br /&gt;
What is the precision of 0 ?&lt;br /&gt;
It cannot be 0 , it only can be the precision of the digital part of the number i.e.  pow(10, -1 * ini_get(&#039;precision&#039;)).&lt;br /&gt;
As a mather of fact the exponent part of 0 is the same one as 1 so its precision is the same.&lt;br /&gt;
We should not forget that the &amp;quot;turning point&amp;quot; (positive to negative)  of real number exponent value is 1 not 0.&lt;br /&gt;
&lt;br /&gt;
So to get the &amp;quot;tiny number&amp;quot; we should multiply the  pow(10, -1 * ini_get(&#039;precision&#039;)) by $this-&amp;gt;answer except when $this-&amp;gt;answer == 0 when it should be 1.&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 0,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;pow(10, -1 * ini_get(&#039;precision&#039;))=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
&lt;br /&gt;
=== Answer is NOT 0===&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;tiny part&amp;quot; should mostly be calculated as pow(10, -1 * ini_get(&#039;precision&#039;))*$answer&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 2,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;=pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))** $this-&amp;gt;answer ;&lt;br /&gt;
&lt;br /&gt;
=Code flow proposal=&lt;br /&gt;
&lt;br /&gt;
This code reflects the discussion although a more concise version could be built.&lt;br /&gt;
The proposal is somehow different from the 1,9 version as it includes the precision of the tolerance in the range.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    if ($this-&amp;gt;answer == 0.0){&lt;br /&gt;
         if($this-&amp;gt;tolerance == 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)){ // the 0&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         }&lt;br /&gt;
   } else {&lt;br /&gt;
         if($this-&amp;gt;tolerance === 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;answer ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)* abs($this-&amp;gt;answer)){ &lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
         }     &lt;br /&gt;
   }         &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Tim&#039;s idea==&lt;br /&gt;
&lt;br /&gt;
I am wondering whether it works just change &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the 2.0 code to&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
max($this-&amp;gt;tolerance, abs($this-&amp;gt;answer), pow(10, -1 * ini_get(&#039;precision&#039;)));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The code might be nicer if we define $epsilon = pow(10, -1 * ini_get(&#039;precision&#039;)) at the start of the function.&lt;br /&gt;
&lt;br /&gt;
Finally, I would like to know what tests you propose to add to question/type/numerical/tests/answer_test.php in order to demonstrate that everything is working properly. In particular, what tests would you like to add that will fail with the current code, but which will pass once we have fixed this bug?&lt;br /&gt;
&lt;br /&gt;
--[[User:Tim Hunt|Tim Hunt]] 00:53, 16 August 2012 (WST)&lt;br /&gt;
==Pierre&#039; comment==&lt;br /&gt;
Thanks for your code expert feedback...&lt;br /&gt;
&lt;br /&gt;
I am using a simple calculated question on 2,0 or a calculated question on 1,9  to test the various combinations with different answers and tolerances.&lt;br /&gt;
&lt;br /&gt;
The range (Min- Max ) is available directly.&lt;br /&gt;
&lt;br /&gt;
At first tests your proposal seems to be working.&lt;br /&gt;
&lt;br /&gt;
[[User:Pierre Pichet|Pierre Pichet]] 07:43, 16 August 2012 (WST)&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34857</id>
		<title>Question Engine 2:Numerical tolerances</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34857"/>
		<updated>2012-08-15T12:27:06Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Analysis of the various tolerances for numerical and calculated question type answer see (MDL-31837)&lt;br /&gt;
&lt;br /&gt;
This is a first version [[User:Pierre Pichet|Pierre Pichet]] 20:27, 15 August 2012 (WST)&lt;br /&gt;
&lt;br /&gt;
In grading a numerical response, the (student) numerical value is compared to the answer numerical value.&lt;br /&gt;
&lt;br /&gt;
This comparison allow a tolerance that is associated with the answer and that can be expressed in various ways.&lt;br /&gt;
&lt;br /&gt;
For calculated question answers the tolerance can be of 3 different types: relative, nominal or geometric. &lt;br /&gt;
=Limits of real numbers in PHP=&lt;br /&gt;
&lt;br /&gt;
The following is from http://www.php.net/manual/en/language.types.float.php&lt;br /&gt;
&lt;br /&gt;
The size of a float is platform-dependent, although a maximum of ~1.8e308 with a precision of roughly 14 decimal digits is a common value (the 64 bit IEEE format).&lt;br /&gt;
&lt;br /&gt;
 Warning&lt;br /&gt;
 Floating point precision&lt;br /&gt;
&lt;br /&gt;
Floating point numbers have limited precision. Although it depends on the system, PHP typically uses the IEEE 754 double precision format, which will give a maximum relative error due to rounding in the order of 1.11e-16. Non elementary arithmetic operations may give larger errors, and, of course, error propagation must be considered when several operations are compounded.&lt;br /&gt;
&lt;br /&gt;
Additionally, rational numbers that are exactly representable as floating point numbers in base 10, like 0.1 or 0.7, do not have an exact representation as floating point numbers in base 2, which is used internally, no matter the size of the mantissa. Hence, they cannot be converted into their internal binary counterparts without a small loss of precision. This can lead to confusing results: for example, floor((0.1+0.7)*10) will usually return 7 instead of the expected 8, since the internal representation will be something like 7.9999999999999991118....&lt;br /&gt;
&lt;br /&gt;
So never trust floating number results to the last digit, and do not compare floating point numbers directly for equality. If higher precision is necessary, the arbitrary precision math functions and gmp functions are available.&lt;br /&gt;
&lt;br /&gt;
Since the internal representation is in base 2, 0 and 1 will have the same exponent so the precision ( i.e. init_get(&#039;precision&#039;) should have the same value.?&lt;br /&gt;
&lt;br /&gt;
....&lt;br /&gt;
=1,9 version=&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
function get_tolerance_interval(&amp;amp;$answer) {&lt;br /&gt;
        // No tolerance&lt;br /&gt;
        if (empty($answer-&amp;gt;tolerance)) {&lt;br /&gt;
            $answer-&amp;gt;tolerance = 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Calculate the interval of correct responses (min/max)&lt;br /&gt;
        if (!isset($answer-&amp;gt;tolerancetype)) {&lt;br /&gt;
            $answer-&amp;gt;tolerancetype = 2; // nominal&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make the&lt;br /&gt;
        // comparison work correctly. Otherwise seemingly equal values can yield&lt;br /&gt;
        // false. (fixes bug #3225)&lt;br /&gt;
        $tolerance = (float)$answer-&amp;gt;tolerance + (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;));&lt;br /&gt;
        switch ($answer-&amp;gt;tolerancetype) {&lt;br /&gt;
            case &#039;1&#039;: case &#039;relative&#039;:&lt;br /&gt;
                /// Recalculate the tolerance and fall through&lt;br /&gt;
                /// to the nominal case:&lt;br /&gt;
                $tolerance = $answer-&amp;gt;answer * $tolerance;&lt;br /&gt;
                // Do not fall through to the nominal case because the tiny fraction is a factor of the answer&lt;br /&gt;
                 $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;2&#039;: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                // $answer-&amp;gt;tolerance 0 or something else&lt;br /&gt;
                if ((float)$answer-&amp;gt;tolerance == 0.0  &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance ){&lt;br /&gt;
                    $tolerance = (float) (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) * abs((float)$answer-&amp;gt;answer) ; //tiny fraction&lt;br /&gt;
                } else if ((float)$answer-&amp;gt;tolerance != 0.0 &amp;amp;&amp;amp; abs((float)$answer-&amp;gt;tolerance) &amp;lt; abs((float)$answer-&amp;gt;answer) &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance){&lt;br /&gt;
                    $tolerance = (1+(&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) )* abs((float) $answer-&amp;gt;tolerance) ;//tiny fraction&lt;br /&gt;
               }&lt;br /&gt;
&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;3&#039;: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                $max = $answer-&amp;gt;answer * $quotient;&lt;br /&gt;
                $min = $answer-&amp;gt;answer / $quotient;&lt;br /&gt;
                break;&lt;br /&gt;
            default:&lt;br /&gt;
                error(&amp;quot;Unknown tolerance type $answer-&amp;gt;tolerancetype&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $answer-&amp;gt;min = $min;&lt;br /&gt;
        $answer-&amp;gt;max = $max;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 actual code=&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class qtype_numerical_answer extends question_answer {&lt;br /&gt;
    /** @var float allowable margin of error. */&lt;br /&gt;
    public $tolerance;&lt;br /&gt;
    /** @var integer|string see {@link get_tolerance_interval()} for the meaning of this value. */&lt;br /&gt;
    public $tolerancetype = 2;&lt;br /&gt;
&lt;br /&gt;
    public function __construct($id, $answer, $fraction, $feedback, $feedbackformat, $tolerance) {&lt;br /&gt;
        parent::__construct($id, $answer, $fraction, $feedback, $feedbackformat);&lt;br /&gt;
        $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_tolerance_interval() {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            throw new coding_exception(&#039;Cannot work out tolerance interval for answer *.&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make&lt;br /&gt;
        // the comparison work correctly, otherwise seemingly equal values can&lt;br /&gt;
        // yield false. See MDL-3225.&lt;br /&gt;
        $tolerance = (float) $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;));&lt;br /&gt;
&lt;br /&gt;
        switch ($this-&amp;gt;tolerancetype) {&lt;br /&gt;
            case 1: case &#039;relative&#039;:&lt;br /&gt;
                $range = abs($this-&amp;gt;answer) * $tolerance;&lt;br /&gt;
                return array($this-&amp;gt;answer - $range, $this-&amp;gt;answer + $range);&lt;br /&gt;
&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) *&lt;br /&gt;
                        max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&lt;br /&gt;
            case 3: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                return array($this-&amp;gt;answer / $quotient, $this-&amp;gt;answer * $quotient);&lt;br /&gt;
&lt;br /&gt;
            default:&lt;br /&gt;
                throw new coding_exception(&#039;Unknown tolerance type &#039; . $this-&amp;gt;tolerancetype);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function within_tolerance($value) {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
        list($min, $max) = $this-&amp;gt;get_tolerance_interval();&lt;br /&gt;
        return $min &amp;lt;= $value &amp;amp;&amp;amp; $value &amp;lt;= $max;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 vs 1,9 differences=&lt;br /&gt;
== case relative ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case geometric ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case nominal ==&lt;br /&gt;
The use of &lt;br /&gt;
 pow(10, -1 * ini_get(&#039;precision&#039;)) * max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
The &#039;tiny fraction&#039; part of the tolerance  is not related to the answer when the answer is less than 1. &lt;br /&gt;
&lt;br /&gt;
We should get back to the 1,9 equivalent code first by removing the max function &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The 1,9 code has a special treatment of the answer == 0 .&lt;br /&gt;
&lt;br /&gt;
Should we keep the code ?&lt;br /&gt;
&lt;br /&gt;
=== Answer is 0===&lt;br /&gt;
What is the precision of 0 ?&lt;br /&gt;
It cannot be 0 , it only can be the precision of the digital part of the number i.e.  pow(10, -1 * ini_get(&#039;precision&#039;)).&lt;br /&gt;
As a mather of fact the exponent part of 0 is the same one as 1 so its precision is the same.&lt;br /&gt;
We should not forget that the &amp;quot;turning point&amp;quot; (positive to negative)  of real number exponent value is 1 not 0.&lt;br /&gt;
&lt;br /&gt;
So to get the &amp;quot;tiny number&amp;quot; we should multiply the  pow(10, -1 * ini_get(&#039;precision&#039;)) by $this-&amp;gt;answer except when $this-&amp;gt;answer == 0 when it should be 1.&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 0,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;pow(10, -1 * ini_get(&#039;precision&#039;))=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
&lt;br /&gt;
=== Answer is NOT 0===&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;tiny part&amp;quot; should mostly be calculated as pow(10, -1 * ini_get(&#039;precision&#039;))*$answer&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 2,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;=pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))** $this-&amp;gt;answer ;&lt;br /&gt;
&lt;br /&gt;
=Code flow proposal=&lt;br /&gt;
&lt;br /&gt;
This code reflects the discussion although a more concise version could be built.&lt;br /&gt;
The proposal is somehow different from the 1,9 version as it includes the precision of the tolerance in the range.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    if ($this-&amp;gt;answer == 0.0){&lt;br /&gt;
         if($this-&amp;gt;tolerance == 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)){ // the 0&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         }&lt;br /&gt;
   } else {&lt;br /&gt;
         if($this-&amp;gt;tolerance === 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;answer ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)* abs($this-&amp;gt;answer)){ &lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
         }     &lt;br /&gt;
   }         &lt;br /&gt;
&amp;lt;/code &amp;gt;&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34856</id>
		<title>Question Engine 2:Numerical tolerances</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34856"/>
		<updated>2012-08-15T12:08:11Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Analysis of the various tolerances for numerical and calculated question type answer (MDL-31837)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;This page is currently built and  NOT completed&#039;&#039;&#039; [[User:Pierre Pichet|Pierre Pichet]] 22:59, 14 August 2012 (WST)&lt;br /&gt;
&lt;br /&gt;
In grading a numerical response, the (student) numerical value is compared to the answer numerical value.&lt;br /&gt;
&lt;br /&gt;
This comparison allow a tolerance that is associated with the answer and that can be expressed in various ways.&lt;br /&gt;
&lt;br /&gt;
For calculated question answers the tolerance can be of 3 different types: relative, nominal or geometric. &lt;br /&gt;
=Limits of real numbers in PHP=&lt;br /&gt;
&lt;br /&gt;
The following is from http://www.php.net/manual/en/language.types.float.php&lt;br /&gt;
&lt;br /&gt;
The size of a float is platform-dependent, although a maximum of ~1.8e308 with a precision of roughly 14 decimal digits is a common value (the 64 bit IEEE format).&lt;br /&gt;
&lt;br /&gt;
 Warning&lt;br /&gt;
 Floating point precision&lt;br /&gt;
&lt;br /&gt;
Floating point numbers have limited precision. Although it depends on the system, PHP typically uses the IEEE 754 double precision format, which will give a maximum relative error due to rounding in the order of 1.11e-16. Non elementary arithmetic operations may give larger errors, and, of course, error propagation must be considered when several operations are compounded.&lt;br /&gt;
&lt;br /&gt;
Additionally, rational numbers that are exactly representable as floating point numbers in base 10, like 0.1 or 0.7, do not have an exact representation as floating point numbers in base 2, which is used internally, no matter the size of the mantissa. Hence, they cannot be converted into their internal binary counterparts without a small loss of precision. This can lead to confusing results: for example, floor((0.1+0.7)*10) will usually return 7 instead of the expected 8, since the internal representation will be something like 7.9999999999999991118....&lt;br /&gt;
&lt;br /&gt;
So never trust floating number results to the last digit, and do not compare floating point numbers directly for equality. If higher precision is necessary, the arbitrary precision math functions and gmp functions are available.&lt;br /&gt;
&lt;br /&gt;
Since the internal representation is in base 2, 0 and 1 will have the same exponent so the precision ( i.e. init_get(&#039;precision&#039;) should have the same value.?&lt;br /&gt;
&lt;br /&gt;
....&lt;br /&gt;
=1,9 version=&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
function get_tolerance_interval(&amp;amp;$answer) {&lt;br /&gt;
        // No tolerance&lt;br /&gt;
        if (empty($answer-&amp;gt;tolerance)) {&lt;br /&gt;
            $answer-&amp;gt;tolerance = 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Calculate the interval of correct responses (min/max)&lt;br /&gt;
        if (!isset($answer-&amp;gt;tolerancetype)) {&lt;br /&gt;
            $answer-&amp;gt;tolerancetype = 2; // nominal&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make the&lt;br /&gt;
        // comparison work correctly. Otherwise seemingly equal values can yield&lt;br /&gt;
        // false. (fixes bug #3225)&lt;br /&gt;
        $tolerance = (float)$answer-&amp;gt;tolerance + (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;));&lt;br /&gt;
        switch ($answer-&amp;gt;tolerancetype) {&lt;br /&gt;
            case &#039;1&#039;: case &#039;relative&#039;:&lt;br /&gt;
                /// Recalculate the tolerance and fall through&lt;br /&gt;
                /// to the nominal case:&lt;br /&gt;
                $tolerance = $answer-&amp;gt;answer * $tolerance;&lt;br /&gt;
                // Do not fall through to the nominal case because the tiny fraction is a factor of the answer&lt;br /&gt;
                 $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;2&#039;: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                // $answer-&amp;gt;tolerance 0 or something else&lt;br /&gt;
                if ((float)$answer-&amp;gt;tolerance == 0.0  &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance ){&lt;br /&gt;
                    $tolerance = (float) (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) * abs((float)$answer-&amp;gt;answer) ; //tiny fraction&lt;br /&gt;
                } else if ((float)$answer-&amp;gt;tolerance != 0.0 &amp;amp;&amp;amp; abs((float)$answer-&amp;gt;tolerance) &amp;lt; abs((float)$answer-&amp;gt;answer) &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance){&lt;br /&gt;
                    $tolerance = (1+(&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) )* abs((float) $answer-&amp;gt;tolerance) ;//tiny fraction&lt;br /&gt;
               }&lt;br /&gt;
&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;3&#039;: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                $max = $answer-&amp;gt;answer * $quotient;&lt;br /&gt;
                $min = $answer-&amp;gt;answer / $quotient;&lt;br /&gt;
                break;&lt;br /&gt;
            default:&lt;br /&gt;
                error(&amp;quot;Unknown tolerance type $answer-&amp;gt;tolerancetype&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $answer-&amp;gt;min = $min;&lt;br /&gt;
        $answer-&amp;gt;max = $max;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 actual code=&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class qtype_numerical_answer extends question_answer {&lt;br /&gt;
    /** @var float allowable margin of error. */&lt;br /&gt;
    public $tolerance;&lt;br /&gt;
    /** @var integer|string see {@link get_tolerance_interval()} for the meaning of this value. */&lt;br /&gt;
    public $tolerancetype = 2;&lt;br /&gt;
&lt;br /&gt;
    public function __construct($id, $answer, $fraction, $feedback, $feedbackformat, $tolerance) {&lt;br /&gt;
        parent::__construct($id, $answer, $fraction, $feedback, $feedbackformat);&lt;br /&gt;
        $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_tolerance_interval() {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            throw new coding_exception(&#039;Cannot work out tolerance interval for answer *.&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make&lt;br /&gt;
        // the comparison work correctly, otherwise seemingly equal values can&lt;br /&gt;
        // yield false. See MDL-3225.&lt;br /&gt;
        $tolerance = (float) $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;));&lt;br /&gt;
&lt;br /&gt;
        switch ($this-&amp;gt;tolerancetype) {&lt;br /&gt;
            case 1: case &#039;relative&#039;:&lt;br /&gt;
                $range = abs($this-&amp;gt;answer) * $tolerance;&lt;br /&gt;
                return array($this-&amp;gt;answer - $range, $this-&amp;gt;answer + $range);&lt;br /&gt;
&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) *&lt;br /&gt;
                        max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&lt;br /&gt;
            case 3: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                return array($this-&amp;gt;answer / $quotient, $this-&amp;gt;answer * $quotient);&lt;br /&gt;
&lt;br /&gt;
            default:&lt;br /&gt;
                throw new coding_exception(&#039;Unknown tolerance type &#039; . $this-&amp;gt;tolerancetype);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function within_tolerance($value) {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
        list($min, $max) = $this-&amp;gt;get_tolerance_interval();&lt;br /&gt;
        return $min &amp;lt;= $value &amp;amp;&amp;amp; $value &amp;lt;= $max;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 vs 1,9 differences=&lt;br /&gt;
== case relative ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case geometric ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case nominal ==&lt;br /&gt;
The use of &lt;br /&gt;
 pow(10, -1 * ini_get(&#039;precision&#039;)) * max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
The &#039;tiny fraction&#039; part of the tolerance  is not related to the answer when the answer is less than 1. &lt;br /&gt;
&lt;br /&gt;
We should get back to the 1,9 equivalent code first by removing the max function &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The 1,9 code has a special treatment of the answer == 0 .&lt;br /&gt;
&lt;br /&gt;
Should we keep the code ?&lt;br /&gt;
&lt;br /&gt;
=== Answer is 0===&lt;br /&gt;
What is the precision of 0 ?&lt;br /&gt;
It cannot be 0 , it only can be the precision of the digital part of the number i.e.  pow(10, -1 * ini_get(&#039;precision&#039;)).&lt;br /&gt;
As a mather of fact the exponent part of 0 is the same one as 1 so its precision is the same.&lt;br /&gt;
We should not forget that the &amp;quot;turning point&amp;quot; (positive to negative)  of real number exponent value is 1 not 0.&lt;br /&gt;
&lt;br /&gt;
So to get the &amp;quot;tiny number&amp;quot; we should multiply the  pow(10, -1 * ini_get(&#039;precision&#039;)) by $this-&amp;gt;answer except when $this-&amp;gt;answer == 0 when it should be 1.&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 0,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;pow(10, -1 * ini_get(&#039;precision&#039;))=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
&lt;br /&gt;
=== Answer is NOT 0===&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;tiny part&amp;quot; should mostly be calculated as pow(10, -1 * ini_get(&#039;precision&#039;))*$answer&lt;br /&gt;
&lt;br /&gt;
===             Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the &amp;quot;tiny part&amp;quot; as a final result;&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))*$answer===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 2,3333333e-24-1/3e24 i.e. &lt;br /&gt;
So &lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
===            Tolerance &amp;gt;=pow(10, -1 * ini_get(&#039;precision&#039;))*$this-&amp;gt;answer=== &lt;br /&gt;
all the other cases&lt;br /&gt;
  $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))** $this-&amp;gt;answer ;&lt;br /&gt;
&lt;br /&gt;
=Code flow proposal==&lt;br /&gt;
&lt;br /&gt;
This code reflects the discussion although a more concise version could be built.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    if ($this-&amp;gt;answer == 0.0){&lt;br /&gt;
         if($this-&amp;gt;tolerance == 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)){ // the 0&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         }&lt;br /&gt;
   } else {&lt;br /&gt;
         if($this-&amp;gt;tolerance === 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;answer ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)* abs($this-&amp;gt;answer)){ &lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
         }     &lt;br /&gt;
   }         &lt;br /&gt;
&amp;lt;/code &amp;gt;&lt;br /&gt;
If the answer is a smaller number than the  pow(10, -1 * ini_get(&#039;precision&#039;))  i.e. 1e-24, then the tiny fraction calculation&lt;br /&gt;
OUPS !!! ....&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
...&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34855</id>
		<title>Question Engine 2:Numerical tolerances</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34855"/>
		<updated>2012-08-15T11:36:06Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Analysis of the various tolerances for numerical and calculated question type answer (MDL-31837)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;This page is currently built and  NOT completed&#039;&#039;&#039; [[User:Pierre Pichet|Pierre Pichet]] 22:59, 14 August 2012 (WST)&lt;br /&gt;
&lt;br /&gt;
In grading a numerical response, the (student) numerical value is compared to the answer numerical value.&lt;br /&gt;
&lt;br /&gt;
This comparison allow a tolerance that is associated with the answer and that can be expressed in various ways.&lt;br /&gt;
&lt;br /&gt;
For calculated question answers the tolerance can be of 3 different types: relative, nominal or geometric. &lt;br /&gt;
=Limits of real numbers in PHP=&lt;br /&gt;
&lt;br /&gt;
The following is from http://www.php.net/manual/en/language.types.float.php&lt;br /&gt;
&lt;br /&gt;
The size of a float is platform-dependent, although a maximum of ~1.8e308 with a precision of roughly 14 decimal digits is a common value (the 64 bit IEEE format).&lt;br /&gt;
&lt;br /&gt;
 Warning&lt;br /&gt;
 Floating point precision&lt;br /&gt;
&lt;br /&gt;
Floating point numbers have limited precision. Although it depends on the system, PHP typically uses the IEEE 754 double precision format, which will give a maximum relative error due to rounding in the order of 1.11e-16. Non elementary arithmetic operations may give larger errors, and, of course, error propagation must be considered when several operations are compounded.&lt;br /&gt;
&lt;br /&gt;
Additionally, rational numbers that are exactly representable as floating point numbers in base 10, like 0.1 or 0.7, do not have an exact representation as floating point numbers in base 2, which is used internally, no matter the size of the mantissa. Hence, they cannot be converted into their internal binary counterparts without a small loss of precision. This can lead to confusing results: for example, floor((0.1+0.7)*10) will usually return 7 instead of the expected 8, since the internal representation will be something like 7.9999999999999991118....&lt;br /&gt;
&lt;br /&gt;
So never trust floating number results to the last digit, and do not compare floating point numbers directly for equality. If higher precision is necessary, the arbitrary precision math functions and gmp functions are available.&lt;br /&gt;
&lt;br /&gt;
Since the internal representation is in base 2, 0 and 1 will have the same exponent so the precision ( i.e. init_get(&#039;precision&#039;) should have the same value.?&lt;br /&gt;
&lt;br /&gt;
....&lt;br /&gt;
=1,9 version=&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
function get_tolerance_interval(&amp;amp;$answer) {&lt;br /&gt;
        // No tolerance&lt;br /&gt;
        if (empty($answer-&amp;gt;tolerance)) {&lt;br /&gt;
            $answer-&amp;gt;tolerance = 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Calculate the interval of correct responses (min/max)&lt;br /&gt;
        if (!isset($answer-&amp;gt;tolerancetype)) {&lt;br /&gt;
            $answer-&amp;gt;tolerancetype = 2; // nominal&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make the&lt;br /&gt;
        // comparison work correctly. Otherwise seemingly equal values can yield&lt;br /&gt;
        // false. (fixes bug #3225)&lt;br /&gt;
        $tolerance = (float)$answer-&amp;gt;tolerance + (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;));&lt;br /&gt;
        switch ($answer-&amp;gt;tolerancetype) {&lt;br /&gt;
            case &#039;1&#039;: case &#039;relative&#039;:&lt;br /&gt;
                /// Recalculate the tolerance and fall through&lt;br /&gt;
                /// to the nominal case:&lt;br /&gt;
                $tolerance = $answer-&amp;gt;answer * $tolerance;&lt;br /&gt;
                // Do not fall through to the nominal case because the tiny fraction is a factor of the answer&lt;br /&gt;
                 $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;2&#039;: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                // $answer-&amp;gt;tolerance 0 or something else&lt;br /&gt;
                if ((float)$answer-&amp;gt;tolerance == 0.0  &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance ){&lt;br /&gt;
                    $tolerance = (float) (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) * abs((float)$answer-&amp;gt;answer) ; //tiny fraction&lt;br /&gt;
                } else if ((float)$answer-&amp;gt;tolerance != 0.0 &amp;amp;&amp;amp; abs((float)$answer-&amp;gt;tolerance) &amp;lt; abs((float)$answer-&amp;gt;answer) &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance){&lt;br /&gt;
                    $tolerance = (1+(&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) )* abs((float) $answer-&amp;gt;tolerance) ;//tiny fraction&lt;br /&gt;
               }&lt;br /&gt;
&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;3&#039;: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                $max = $answer-&amp;gt;answer * $quotient;&lt;br /&gt;
                $min = $answer-&amp;gt;answer / $quotient;&lt;br /&gt;
                break;&lt;br /&gt;
            default:&lt;br /&gt;
                error(&amp;quot;Unknown tolerance type $answer-&amp;gt;tolerancetype&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $answer-&amp;gt;min = $min;&lt;br /&gt;
        $answer-&amp;gt;max = $max;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 actual code=&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class qtype_numerical_answer extends question_answer {&lt;br /&gt;
    /** @var float allowable margin of error. */&lt;br /&gt;
    public $tolerance;&lt;br /&gt;
    /** @var integer|string see {@link get_tolerance_interval()} for the meaning of this value. */&lt;br /&gt;
    public $tolerancetype = 2;&lt;br /&gt;
&lt;br /&gt;
    public function __construct($id, $answer, $fraction, $feedback, $feedbackformat, $tolerance) {&lt;br /&gt;
        parent::__construct($id, $answer, $fraction, $feedback, $feedbackformat);&lt;br /&gt;
        $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_tolerance_interval() {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            throw new coding_exception(&#039;Cannot work out tolerance interval for answer *.&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make&lt;br /&gt;
        // the comparison work correctly, otherwise seemingly equal values can&lt;br /&gt;
        // yield false. See MDL-3225.&lt;br /&gt;
        $tolerance = (float) $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;));&lt;br /&gt;
&lt;br /&gt;
        switch ($this-&amp;gt;tolerancetype) {&lt;br /&gt;
            case 1: case &#039;relative&#039;:&lt;br /&gt;
                $range = abs($this-&amp;gt;answer) * $tolerance;&lt;br /&gt;
                return array($this-&amp;gt;answer - $range, $this-&amp;gt;answer + $range);&lt;br /&gt;
&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) *&lt;br /&gt;
                        max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&lt;br /&gt;
            case 3: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                return array($this-&amp;gt;answer / $quotient, $this-&amp;gt;answer * $quotient);&lt;br /&gt;
&lt;br /&gt;
            default:&lt;br /&gt;
                throw new coding_exception(&#039;Unknown tolerance type &#039; . $this-&amp;gt;tolerancetype);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function within_tolerance($value) {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
        list($min, $max) = $this-&amp;gt;get_tolerance_interval();&lt;br /&gt;
        return $min &amp;lt;= $value &amp;amp;&amp;amp; $value &amp;lt;= $max;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 vs 1,9 differences=&lt;br /&gt;
== case relative ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case geometric ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case nominal ==&lt;br /&gt;
The use of &lt;br /&gt;
 pow(10, -1 * ini_get(&#039;precision&#039;)) * max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
The &#039;tiny fraction&#039; part of the tolerance  is not related to the answer when the answer is less than 1. &lt;br /&gt;
&lt;br /&gt;
We should get back to the 1,9 equivalent code first by removing the max function &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The 1,9 code has a special treatment of the answer == 0 .&lt;br /&gt;
&lt;br /&gt;
Should we keep the code ?&lt;br /&gt;
&lt;br /&gt;
=== Answer is 0===&lt;br /&gt;
What is the precision of 0 ?&lt;br /&gt;
It cannot be 0 , it only can be the precision of the digital part of the number i.e.  pow(10, -1 * ini_get(&#039;precision&#039;)).&lt;br /&gt;
As a mather of fact the exponent part of 0 is the same one as 1 so its precision is the same.&lt;br /&gt;
We should not forget that the &amp;quot;turning point&amp;quot; (positive to negative)  of real number exponent value is 1 not 0.&lt;br /&gt;
&lt;br /&gt;
So to get the &amp;quot;tiny number&amp;quot; we should multiply the  pow(10, -1 * ini_get(&#039;precision&#039;)) by $this-&amp;gt;answer except when $this-&amp;gt;answer == 0 when it should be 1.&lt;br /&gt;
&lt;br /&gt;
===Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the tiny part as a final result;&lt;br /&gt;
&lt;br /&gt;
===Tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;))===&lt;br /&gt;
The tolerance i.e 1e-26  should become the number that control the process and define the &amp;quot;tiny number&amp;quot;.&lt;br /&gt;
So &lt;br /&gt;
 $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
&lt;br /&gt;
Such a case could result when the 0 answer comes from  something like 0,3333333e-24-1/3e24 i.e. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The addition process of&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    if ($this-&amp;gt;answer === 0.0){&lt;br /&gt;
         if($this-&amp;gt;tolerance === 0.0){&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ;&lt;br /&gt;
         } else if( $this-&amp;gt;tolerance &amp;lt;  pow(10, -1 * ini_get(&#039;precision&#039;)){ // the 0&lt;br /&gt;
               $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;))* $this-&amp;gt;tolerance ; &lt;br /&gt;
         }else {&lt;br /&gt;
              $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
         }&lt;br /&gt;
   } else {&lt;br /&gt;
        $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
   }         &lt;br /&gt;
&amp;lt;/code &amp;gt;&lt;br /&gt;
If the answer is a smaller number than the  pow(10, -1 * ini_get(&#039;precision&#039;))  i.e. 1e-24, then the tiny fraction calculation&lt;br /&gt;
OUPS !!! ....&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
...&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34842</id>
		<title>Question Engine 2:Numerical tolerances</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34842"/>
		<updated>2012-08-15T03:42:36Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: /* case nominal */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Analysis of the various tolerances for numerical and calculated question type answer (MDL-31837)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;This page is currently built and  NOT completed&#039;&#039;&#039; [[User:Pierre Pichet|Pierre Pichet]] 22:59, 14 August 2012 (WST)&lt;br /&gt;
&lt;br /&gt;
In grading a numerical response, the (student) numerical value is compared to the answer numerical value.&lt;br /&gt;
&lt;br /&gt;
This comparison allow a tolerance that is associated with the answer and that can be expressed in various ways.&lt;br /&gt;
&lt;br /&gt;
For calculated question answers the tolerance can be of 3 different types: relative, nominal or geometric. &lt;br /&gt;
=Limits of real numbers in PHP=&lt;br /&gt;
&lt;br /&gt;
The following is from http://www.php.net/manual/en/language.types.float.php&lt;br /&gt;
&lt;br /&gt;
The size of a float is platform-dependent, although a maximum of ~1.8e308 with a precision of roughly 14 decimal digits is a common value (the 64 bit IEEE format).&lt;br /&gt;
&lt;br /&gt;
 Warning&lt;br /&gt;
 Floating point precision&lt;br /&gt;
&lt;br /&gt;
Floating point numbers have limited precision. Although it depends on the system, PHP typically uses the IEEE 754 double precision format, which will give a maximum relative error due to rounding in the order of 1.11e-16. Non elementary arithmetic operations may give larger errors, and, of course, error propagation must be considered when several operations are compounded.&lt;br /&gt;
&lt;br /&gt;
Additionally, rational numbers that are exactly representable as floating point numbers in base 10, like 0.1 or 0.7, do not have an exact representation as floating point numbers in base 2, which is used internally, no matter the size of the mantissa. Hence, they cannot be converted into their internal binary counterparts without a small loss of precision. This can lead to confusing results: for example, floor((0.1+0.7)*10) will usually return 7 instead of the expected 8, since the internal representation will be something like 7.9999999999999991118....&lt;br /&gt;
&lt;br /&gt;
So never trust floating number results to the last digit, and do not compare floating point numbers directly for equality. If higher precision is necessary, the arbitrary precision math functions and gmp functions are available.&lt;br /&gt;
&lt;br /&gt;
Since the internal representation is in base 2, 0 and 1 will have the same exponent so the precision ( i.e. init_get(&#039;precision&#039;) should have the same value.?&lt;br /&gt;
&lt;br /&gt;
....&lt;br /&gt;
=1,9 version=&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
function get_tolerance_interval(&amp;amp;$answer) {&lt;br /&gt;
        // No tolerance&lt;br /&gt;
        if (empty($answer-&amp;gt;tolerance)) {&lt;br /&gt;
            $answer-&amp;gt;tolerance = 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Calculate the interval of correct responses (min/max)&lt;br /&gt;
        if (!isset($answer-&amp;gt;tolerancetype)) {&lt;br /&gt;
            $answer-&amp;gt;tolerancetype = 2; // nominal&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make the&lt;br /&gt;
        // comparison work correctly. Otherwise seemingly equal values can yield&lt;br /&gt;
        // false. (fixes bug #3225)&lt;br /&gt;
        $tolerance = (float)$answer-&amp;gt;tolerance + (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;));&lt;br /&gt;
        switch ($answer-&amp;gt;tolerancetype) {&lt;br /&gt;
            case &#039;1&#039;: case &#039;relative&#039;:&lt;br /&gt;
                /// Recalculate the tolerance and fall through&lt;br /&gt;
                /// to the nominal case:&lt;br /&gt;
                $tolerance = $answer-&amp;gt;answer * $tolerance;&lt;br /&gt;
                // Do not fall through to the nominal case because the tiny fraction is a factor of the answer&lt;br /&gt;
                 $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;2&#039;: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                // $answer-&amp;gt;tolerance 0 or something else&lt;br /&gt;
                if ((float)$answer-&amp;gt;tolerance == 0.0  &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance ){&lt;br /&gt;
                    $tolerance = (float) (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) * abs((float)$answer-&amp;gt;answer) ; //tiny fraction&lt;br /&gt;
                } else if ((float)$answer-&amp;gt;tolerance != 0.0 &amp;amp;&amp;amp; abs((float)$answer-&amp;gt;tolerance) &amp;lt; abs((float)$answer-&amp;gt;answer) &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance){&lt;br /&gt;
                    $tolerance = (1+(&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) )* abs((float) $answer-&amp;gt;tolerance) ;//tiny fraction&lt;br /&gt;
               }&lt;br /&gt;
&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;3&#039;: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                $max = $answer-&amp;gt;answer * $quotient;&lt;br /&gt;
                $min = $answer-&amp;gt;answer / $quotient;&lt;br /&gt;
                break;&lt;br /&gt;
            default:&lt;br /&gt;
                error(&amp;quot;Unknown tolerance type $answer-&amp;gt;tolerancetype&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $answer-&amp;gt;min = $min;&lt;br /&gt;
        $answer-&amp;gt;max = $max;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 actual code=&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class qtype_numerical_answer extends question_answer {&lt;br /&gt;
    /** @var float allowable margin of error. */&lt;br /&gt;
    public $tolerance;&lt;br /&gt;
    /** @var integer|string see {@link get_tolerance_interval()} for the meaning of this value. */&lt;br /&gt;
    public $tolerancetype = 2;&lt;br /&gt;
&lt;br /&gt;
    public function __construct($id, $answer, $fraction, $feedback, $feedbackformat, $tolerance) {&lt;br /&gt;
        parent::__construct($id, $answer, $fraction, $feedback, $feedbackformat);&lt;br /&gt;
        $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_tolerance_interval() {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            throw new coding_exception(&#039;Cannot work out tolerance interval for answer *.&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make&lt;br /&gt;
        // the comparison work correctly, otherwise seemingly equal values can&lt;br /&gt;
        // yield false. See MDL-3225.&lt;br /&gt;
        $tolerance = (float) $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;));&lt;br /&gt;
&lt;br /&gt;
        switch ($this-&amp;gt;tolerancetype) {&lt;br /&gt;
            case 1: case &#039;relative&#039;:&lt;br /&gt;
                $range = abs($this-&amp;gt;answer) * $tolerance;&lt;br /&gt;
                return array($this-&amp;gt;answer - $range, $this-&amp;gt;answer + $range);&lt;br /&gt;
&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) *&lt;br /&gt;
                        max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&lt;br /&gt;
            case 3: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                return array($this-&amp;gt;answer / $quotient, $this-&amp;gt;answer * $quotient);&lt;br /&gt;
&lt;br /&gt;
            default:&lt;br /&gt;
                throw new coding_exception(&#039;Unknown tolerance type &#039; . $this-&amp;gt;tolerancetype);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function within_tolerance($value) {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
        list($min, $max) = $this-&amp;gt;get_tolerance_interval();&lt;br /&gt;
        return $min &amp;lt;= $value &amp;amp;&amp;amp; $value &amp;lt;= $max;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 vs 1,9 differences=&lt;br /&gt;
== case relative ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case geometric ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case nominal ==&lt;br /&gt;
The use of &lt;br /&gt;
 pow(10, -1 * ini_get(&#039;precision&#039;)) * max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
The &#039;tiny fraction&#039; part of the tolerance  is not related to the answer when the answer is less than 1. &lt;br /&gt;
&lt;br /&gt;
We should get back to the 1,9 equivalent code first by removing the max function &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The 1,9 code has a special treatment of the answer == 0 .&lt;br /&gt;
&lt;br /&gt;
Should we keep the code ?&lt;br /&gt;
&lt;br /&gt;
=== Answer is 0===&lt;br /&gt;
What is the precision of 0 ?&lt;br /&gt;
It cannot be 0 , it only can be the precision of the digital part of the number i.e.  pow(10, -1 * ini_get(&#039;precision&#039;)).&lt;br /&gt;
As a mather of fact the exponent part of 0 is the same one as 1 so its precision is the same.&lt;br /&gt;
We should not forget that the &amp;quot;turning point&amp;quot; of real number exponent value is 1 not 0.&lt;br /&gt;
&lt;br /&gt;
So to get the &amp;quot;tiny number&amp;quot; we should multiply the  pow(10, -1 * ini_get(&#039;precision&#039;)) by $this-&amp;gt;answer except when $this-&amp;gt;answer == 0 when it should be 1.&lt;br /&gt;
&lt;br /&gt;
===Tolerance is 0===&lt;br /&gt;
The 0 value should be used as is, the php should only retain the tiny part as a final result;&lt;br /&gt;
&lt;br /&gt;
The addition process of&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    if ($this-&amp;gt;answer === 0.0){  &lt;br /&gt;
         $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) ;&lt;br /&gt;
   } else {&lt;br /&gt;
        $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) * abs($this-&amp;gt;answer);&lt;br /&gt;
   }         &lt;br /&gt;
&amp;lt;/code &amp;gt;&lt;br /&gt;
If the answer is a smaller number than the  pow(10, -1 * ini_get(&#039;precision&#039;))  i.e. 1e-24, then the tiny fraction calculation&lt;br /&gt;
OUPS !!! ....&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
...&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34830</id>
		<title>Question Engine 2:Numerical tolerances</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34830"/>
		<updated>2012-08-15T02:23:20Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Analysis of the various tolerances for numerical and calculated question type answer (MDL-31837)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;This page is currently built and  NOT completed&#039;&#039;&#039; [[User:Pierre Pichet|Pierre Pichet]] 22:59, 14 August 2012 (WST)&lt;br /&gt;
&lt;br /&gt;
In grading a numerical response, the (student) numerical value is compared to the answer numerical value.&lt;br /&gt;
&lt;br /&gt;
This comparison allow a tolerance that is associated with the answer and that can be expressed in various ways.&lt;br /&gt;
&lt;br /&gt;
For calculated question answers the tolerance can be of 3 different types: relative, nominal or geometric. &lt;br /&gt;
=Limits of real numbers in PHP=&lt;br /&gt;
&lt;br /&gt;
The following is from http://www.php.net/manual/en/language.types.float.php&lt;br /&gt;
&lt;br /&gt;
The size of a float is platform-dependent, although a maximum of ~1.8e308 with a precision of roughly 14 decimal digits is a common value (the 64 bit IEEE format).&lt;br /&gt;
&lt;br /&gt;
 Warning&lt;br /&gt;
 Floating point precision&lt;br /&gt;
&lt;br /&gt;
Floating point numbers have limited precision. Although it depends on the system, PHP typically uses the IEEE 754 double precision format, which will give a maximum relative error due to rounding in the order of 1.11e-16. Non elementary arithmetic operations may give larger errors, and, of course, error propagation must be considered when several operations are compounded.&lt;br /&gt;
&lt;br /&gt;
Additionally, rational numbers that are exactly representable as floating point numbers in base 10, like 0.1 or 0.7, do not have an exact representation as floating point numbers in base 2, which is used internally, no matter the size of the mantissa. Hence, they cannot be converted into their internal binary counterparts without a small loss of precision. This can lead to confusing results: for example, floor((0.1+0.7)*10) will usually return 7 instead of the expected 8, since the internal representation will be something like 7.9999999999999991118....&lt;br /&gt;
&lt;br /&gt;
So never trust floating number results to the last digit, and do not compare floating point numbers directly for equality. If higher precision is necessary, the arbitrary precision math functions and gmp functions are available.&lt;br /&gt;
&lt;br /&gt;
Since the internal representation is in base 2, 0 and 1 will have the same exponent so the precision ( i.e. init_get(&#039;precision&#039;) should have the same value.?&lt;br /&gt;
&lt;br /&gt;
....&lt;br /&gt;
=1,9 version=&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
function get_tolerance_interval(&amp;amp;$answer) {&lt;br /&gt;
        // No tolerance&lt;br /&gt;
        if (empty($answer-&amp;gt;tolerance)) {&lt;br /&gt;
            $answer-&amp;gt;tolerance = 0;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Calculate the interval of correct responses (min/max)&lt;br /&gt;
        if (!isset($answer-&amp;gt;tolerancetype)) {&lt;br /&gt;
            $answer-&amp;gt;tolerancetype = 2; // nominal&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make the&lt;br /&gt;
        // comparison work correctly. Otherwise seemingly equal values can yield&lt;br /&gt;
        // false. (fixes bug #3225)&lt;br /&gt;
        $tolerance = (float)$answer-&amp;gt;tolerance + (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;));&lt;br /&gt;
        switch ($answer-&amp;gt;tolerancetype) {&lt;br /&gt;
            case &#039;1&#039;: case &#039;relative&#039;:&lt;br /&gt;
                /// Recalculate the tolerance and fall through&lt;br /&gt;
                /// to the nominal case:&lt;br /&gt;
                $tolerance = $answer-&amp;gt;answer * $tolerance;&lt;br /&gt;
                // Do not fall through to the nominal case because the tiny fraction is a factor of the answer&lt;br /&gt;
                 $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;2&#039;: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = abs($tolerance); // important - otherwise min and max are swapped&lt;br /&gt;
                // $answer-&amp;gt;tolerance 0 or something else&lt;br /&gt;
                if ((float)$answer-&amp;gt;tolerance == 0.0  &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance ){&lt;br /&gt;
                    $tolerance = (float) (&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) * abs((float)$answer-&amp;gt;answer) ; //tiny fraction&lt;br /&gt;
                } else if ((float)$answer-&amp;gt;tolerance != 0.0 &amp;amp;&amp;amp; abs((float)$answer-&amp;gt;tolerance) &amp;lt; abs((float)$answer-&amp;gt;answer) &amp;amp;&amp;amp;  abs((float)$answer-&amp;gt;answer) &amp;lt;= $tolerance){&lt;br /&gt;
                    $tolerance = (1+(&amp;quot;1.0e-&amp;quot;.ini_get(&#039;precision&#039;)) )* abs((float) $answer-&amp;gt;tolerance) ;//tiny fraction&lt;br /&gt;
               }&lt;br /&gt;
&lt;br /&gt;
                $max = $answer-&amp;gt;answer + $tolerance;&lt;br /&gt;
                $min = $answer-&amp;gt;answer - $tolerance;&lt;br /&gt;
                break;&lt;br /&gt;
            case &#039;3&#039;: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                $max = $answer-&amp;gt;answer * $quotient;&lt;br /&gt;
                $min = $answer-&amp;gt;answer / $quotient;&lt;br /&gt;
                break;&lt;br /&gt;
            default:&lt;br /&gt;
                error(&amp;quot;Unknown tolerance type $answer-&amp;gt;tolerancetype&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $answer-&amp;gt;min = $min;&lt;br /&gt;
        $answer-&amp;gt;max = $max;&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 actual code=&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class qtype_numerical_answer extends question_answer {&lt;br /&gt;
    /** @var float allowable margin of error. */&lt;br /&gt;
    public $tolerance;&lt;br /&gt;
    /** @var integer|string see {@link get_tolerance_interval()} for the meaning of this value. */&lt;br /&gt;
    public $tolerancetype = 2;&lt;br /&gt;
&lt;br /&gt;
    public function __construct($id, $answer, $fraction, $feedback, $feedbackformat, $tolerance) {&lt;br /&gt;
        parent::__construct($id, $answer, $fraction, $feedback, $feedbackformat);&lt;br /&gt;
        $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_tolerance_interval() {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            throw new coding_exception(&#039;Cannot work out tolerance interval for answer *.&#039;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // We need to add a tiny fraction depending on the set precision to make&lt;br /&gt;
        // the comparison work correctly, otherwise seemingly equal values can&lt;br /&gt;
        // yield false. See MDL-3225.&lt;br /&gt;
        $tolerance = (float) $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;));&lt;br /&gt;
&lt;br /&gt;
        switch ($this-&amp;gt;tolerancetype) {&lt;br /&gt;
            case 1: case &#039;relative&#039;:&lt;br /&gt;
                $range = abs($this-&amp;gt;answer) * $tolerance;&lt;br /&gt;
                return array($this-&amp;gt;answer - $range, $this-&amp;gt;answer + $range);&lt;br /&gt;
&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) *&lt;br /&gt;
                        max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&lt;br /&gt;
            case 3: case &#039;geometric&#039;:&lt;br /&gt;
                $quotient = 1 + abs($tolerance);&lt;br /&gt;
                return array($this-&amp;gt;answer / $quotient, $this-&amp;gt;answer * $quotient);&lt;br /&gt;
&lt;br /&gt;
            default:&lt;br /&gt;
                throw new coding_exception(&#039;Unknown tolerance type &#039; . $this-&amp;gt;tolerancetype);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function within_tolerance($value) {&lt;br /&gt;
        if ($this-&amp;gt;answer === &#039;*&#039;) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
        list($min, $max) = $this-&amp;gt;get_tolerance_interval();&lt;br /&gt;
        return $min &amp;lt;= $value &amp;amp;&amp;amp; $value &amp;lt;= $max;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
=2,0 vs 1,9 differences=&lt;br /&gt;
== case relative ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case geometric ==&lt;br /&gt;
The math treatment is equivalent as &lt;br /&gt;
 $this-&amp;gt;tolerance = abs($tolerance);&lt;br /&gt;
&lt;br /&gt;
== case nominal ==&lt;br /&gt;
The use of &lt;br /&gt;
 pow(10, -1 * ini_get(&#039;precision&#039;)) * max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
The &#039;tiny fraction&#039; part of the tolerance  is not related to the answer when the answer is less than 1. &lt;br /&gt;
&lt;br /&gt;
We should get back to the 1,9 equivalent code first by removing the max function &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
            case 2: case &#039;nominal&#039;:&lt;br /&gt;
                $tolerance = $this-&amp;gt;tolerance + pow(10, -1 * ini_get(&#039;precision&#039;)) *&lt;br /&gt;
                        max(1, abs($this-&amp;gt;answer));&lt;br /&gt;
                return array($this-&amp;gt;answer - $tolerance, $this-&amp;gt;answer + $tolerance);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The 1,9 code has a special treatment of the answer == 0 .&lt;br /&gt;
&lt;br /&gt;
Should we keep the code ?&lt;br /&gt;
&lt;br /&gt;
=== Answer is 0===&lt;br /&gt;
If the answer is a smaller number than the  pow(10, -1 * ini_get(&#039;precision&#039;))  i.e. 1e-24, then the tiny fraction calculation....&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
...&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34827</id>
		<title>Question Engine 2:Numerical tolerances</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34827"/>
		<updated>2012-08-14T16:41:10Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Analysis of the various tolerances for numerical and calculated question type answer (MDL-31837)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;This page is currently built and  NOT completed&#039;&#039;&#039; [[User:Pierre Pichet|Pierre Pichet]] 22:59, 14 August 2012 (WST)&lt;br /&gt;
&lt;br /&gt;
In grading a numerical response, the (student) numerical value is compared to the answer numerical value.&lt;br /&gt;
&lt;br /&gt;
This comparison allow a tolerance that is associated with the answer and that can be expressed in various ways.&lt;br /&gt;
&lt;br /&gt;
For calculated question answers the tolerance can be of 3 different types: relative, nominal or geometric. &lt;br /&gt;
&lt;br /&gt;
The following is from http://www.php.net/manual/en/language.types.float.php&lt;br /&gt;
&lt;br /&gt;
The size of a float is platform-dependent, although a maximum of ~1.8e308 with a precision of roughly 14 decimal digits is a common value (the 64 bit IEEE format).&lt;br /&gt;
&lt;br /&gt;
 Warning&lt;br /&gt;
 Floating point precision&lt;br /&gt;
&lt;br /&gt;
Floating point numbers have limited precision. Although it depends on the system, PHP typically uses the IEEE 754 double precision format, which will give a maximum relative error due to rounding in the order of 1.11e-16. Non elementary arithmetic operations may give larger errors, and, of course, error propagation must be considered when several operations are compounded.&lt;br /&gt;
&lt;br /&gt;
Additionally, rational numbers that are exactly representable as floating point numbers in base 10, like 0.1 or 0.7, do not have an exact representation as floating point numbers in base 2, which is used internally, no matter the size of the mantissa. Hence, they cannot be converted into their internal binary counterparts without a small loss of precision. This can lead to confusing results: for example, floor((0.1+0.7)*10) will usually return 7 instead of the expected 8, since the internal representation will be something like 7.9999999999999991118....&lt;br /&gt;
&lt;br /&gt;
So never trust floating number results to the last digit, and do not compare floating point numbers directly for equality. If higher precision is necessary, the arbitrary precision math functions and gmp functions are available.&lt;br /&gt;
&lt;br /&gt;
Since the internal representation is in base 2, 0 and 1 will have the same exponent so the precision ( i.e. init_get(&#039;precision&#039;) should have the same value.?&lt;br /&gt;
&lt;br /&gt;
....&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34826</id>
		<title>Question Engine 2:Numerical tolerances</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34826"/>
		<updated>2012-08-14T14:59:19Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Analysis of the various tolerances for numerical and calculated question type answer (MDL-31837)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;This page is currently built and  NOT completed&#039;&#039;&#039; [[User:Pierre Pichet|Pierre Pichet]] 22:59, 14 August 2012 (WST)&lt;br /&gt;
&lt;br /&gt;
In grading a numerical response, the (student) numerical value is compared to the answer numerical value.&lt;br /&gt;
&lt;br /&gt;
This comparison allow a tolerance that is associated with the answer and that can be expressed in various ways.&lt;br /&gt;
&lt;br /&gt;
For calculated question answers the tolerance can be of 3 different types: relative, nominal or geometric. &lt;br /&gt;
&lt;br /&gt;
The following is from http://www.php.net/manual/en/language.types.float.php&lt;br /&gt;
&lt;br /&gt;
The size of a float is platform-dependent, although a maximum of ~1.8e308 with a precision of roughly 14 decimal digits is a common value (the 64 bit IEEE format).&lt;br /&gt;
&lt;br /&gt;
Warning&lt;br /&gt;
Floating point precision&lt;br /&gt;
&lt;br /&gt;
Floating point numbers have limited precision. Although it depends on the system, PHP typically uses the IEEE 754 double precision format, which will give a maximum relative error due to rounding in the order of 1.11e-16. Non elementary arithmetic operations may give larger errors, and, of course, error propagation must be considered when several operations are compounded.&lt;br /&gt;
&lt;br /&gt;
Additionally, rational numbers that are exactly representable as floating point numbers in base 10, like 0.1 or 0.7, do not have an exact representation as floating point numbers in base 2, which is used internally, no matter the size of the mantissa. Hence, they cannot be converted into their internal binary counterparts without a small loss of precision. This can lead to confusing results: for example, floor((0.1+0.7)*10) will usually return 7 instead of the expected 8, since the internal representation will be something like 7.9999999999999991118....&lt;br /&gt;
&lt;br /&gt;
So never trust floating number results to the last digit, and do not compare floating point numbers directly for equality. If higher precision is necessary, the arbitrary precision math functions and gmp functions are available.&lt;br /&gt;
&lt;br /&gt;
....&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34802</id>
		<title>Question Engine 2:Numerical tolerances</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Question_Engine_2:Numerical_tolerances&amp;diff=34802"/>
		<updated>2012-08-14T04:43:38Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: Created page with &amp;quot;Analysis of the various tolerances for numerical and calculated question type answer (MDL-31837)  In grading a numerical response, the (student) numerical value is compared to th...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Analysis of the various tolerances for numerical and calculated question type answer (MDL-31837)&lt;br /&gt;
&lt;br /&gt;
In grading a numerical response, the (student) numerical value is compared to the answer numerical value.&lt;br /&gt;
&lt;br /&gt;
This comparison allow a tolerance that is associated with the answer and that can be expressed in various ways.&lt;br /&gt;
&lt;br /&gt;
For calculated question answers the tolerance can be of 3 different types: relative, nominal or geometric. &lt;br /&gt;
&lt;br /&gt;
....&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Numerical_question_type&amp;diff=34801</id>
		<title>Numerical question type</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Numerical_question_type&amp;diff=34801"/>
		<updated>2012-08-14T04:25:41Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: /* See also */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Questiontype developer docs}}&lt;br /&gt;
&lt;br /&gt;
==Database tables==&lt;br /&gt;
&lt;br /&gt;
===quiz_numerical===&lt;br /&gt;
&lt;br /&gt;
The quiz_numerical table is an extension of the quiz_answers table, defining a tolerance value for each answer.&lt;br /&gt;
&lt;br /&gt;
;id :int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
;question :int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
;answer :int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
;tolerance :varchar(255) NOT NULL default &#039;0.0&#039;,&lt;br /&gt;
&lt;br /&gt;
===quiz_numerical_units===&lt;br /&gt;
&lt;br /&gt;
The quiz_numerical_units table is used by the numerical questiontype and the calculated questionype. It extends the quiz_questions table, defining an arbitrary number of units that can be used in the responses.&lt;br /&gt;
&lt;br /&gt;
;id :int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
;question :int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
;multiplier :decimal(40,20) NOT NULL default &#039;1.00000000000000000000&#039;,&lt;br /&gt;
;unit :varchar(50) NOT NULL default &#039;&#039;,&lt;br /&gt;
&lt;br /&gt;
==Response storage==&lt;br /&gt;
&lt;br /&gt;
The numerical questiontype, which inherits the function print_question_formulation_and_controls() from the shortanswer questiontype, has only one response field, so its responses are handled by the default questiontype. The response is stored without any modifications in the answer field of the table quiz_states.&lt;br /&gt;
&lt;br /&gt;
==Question-&amp;gt;options==&lt;br /&gt;
&lt;br /&gt;
==State-&amp;gt;options==&lt;br /&gt;
&lt;br /&gt;
[[Category:Quiz]]&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
[[Question Engine 2:Numerical formats |Numerical formats]], gives a proposal for implementing various numerical formats for numerical and calculated question type in Question Engine 2.1.&lt;br /&gt;
&lt;br /&gt;
[[Question Engine 2:Numerical tolerances |Numerical tolerances]], analysis of the various tolerances for numerical and calculated question type answer (MDL-31837).&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Numerical_question_type&amp;diff=34800</id>
		<title>Numerical question type</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Numerical_question_type&amp;diff=34800"/>
		<updated>2012-08-14T04:25:10Z</updated>

		<summary type="html">&lt;p&gt;Ppichet: /* See also */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Questiontype developer docs}}&lt;br /&gt;
&lt;br /&gt;
==Database tables==&lt;br /&gt;
&lt;br /&gt;
===quiz_numerical===&lt;br /&gt;
&lt;br /&gt;
The quiz_numerical table is an extension of the quiz_answers table, defining a tolerance value for each answer.&lt;br /&gt;
&lt;br /&gt;
;id :int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
;question :int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
;answer :int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
;tolerance :varchar(255) NOT NULL default &#039;0.0&#039;,&lt;br /&gt;
&lt;br /&gt;
===quiz_numerical_units===&lt;br /&gt;
&lt;br /&gt;
The quiz_numerical_units table is used by the numerical questiontype and the calculated questionype. It extends the quiz_questions table, defining an arbitrary number of units that can be used in the responses.&lt;br /&gt;
&lt;br /&gt;
;id :int(10) unsigned NOT NULL auto_increment,&lt;br /&gt;
;question :int(10) unsigned NOT NULL default &#039;0&#039;,&lt;br /&gt;
;multiplier :decimal(40,20) NOT NULL default &#039;1.00000000000000000000&#039;,&lt;br /&gt;
;unit :varchar(50) NOT NULL default &#039;&#039;,&lt;br /&gt;
&lt;br /&gt;
==Response storage==&lt;br /&gt;
&lt;br /&gt;
The numerical questiontype, which inherits the function print_question_formulation_and_controls() from the shortanswer questiontype, has only one response field, so its responses are handled by the default questiontype. The response is stored without any modifications in the answer field of the table quiz_states.&lt;br /&gt;
&lt;br /&gt;
==Question-&amp;gt;options==&lt;br /&gt;
&lt;br /&gt;
==State-&amp;gt;options==&lt;br /&gt;
&lt;br /&gt;
[[Category:Quiz]]&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
[[Question Engine 2:Numerical formats |Numerical formats]], gives a proposal for implementing various numerical formats for numerical and calculated question type in Question Engine 2.1.&lt;br /&gt;
&lt;br /&gt;
[[Question Engine 2:Numerical tolerances |Numerical tolerance]], analysis of the various tolerances for numerical and calculated question type answer (MDL-31837).&lt;/div&gt;</summary>
		<author><name>Ppichet</name></author>
	</entry>
</feed>