Commit 4388bff8 by Alexander Kryklia

Merge pull request #2150 from edx/anton/fix-negative-exponents

Anton/fix negative exponents
parents cbe97d6f 1347645e
......@@ -5,6 +5,8 @@ These are notable changes in edx-platform. This is a rolling list of changes,
in roughly chronological order, most recent first. Add your entries at or near
the top. Include a label indicating the component affected.
Blades: Fix comparison of float numbers. BLD-434.
Blades: Allow regexp strings as the correct answer to a string response question. BLD-475.
Common: Add feature flags to allow developer use of pure XBlocks
......
......@@ -35,7 +35,8 @@ from calc import evaluator, UndefinedVariable
from . import correctmap
from datetime import datetime
from pytz import UTC
from .util import compare_with_tolerance, contextualize_text, convert_files_to_filenames, is_list_of_files, find_with_default
from .util import (compare_with_tolerance, contextualize_text, convert_files_to_filenames,
is_list_of_files, find_with_default, default_tolerance)
from lxml import etree
from lxml.html.soupparser import fromstring as fromstring_bs # uses Beautiful Soup!!! FIXME?
import capa.xqueue_interface as xqueue_interface
......@@ -832,7 +833,7 @@ class NumericalResponse(LoncapaResponse):
def __init__(self, *args, **kwargs):
self.correct_answer = ''
self.tolerance = '0' # Default value
self.tolerance = default_tolerance
super(NumericalResponse, self).__init__(*args, **kwargs)
def setup_response(self):
......@@ -1877,7 +1878,7 @@ class FormulaResponse(LoncapaResponse):
def __init__(self, *args, **kwargs):
self.correct_answer = ''
self.samples = ''
self.tolerance = '1e-5' # Default value
self.tolerance = default_tolerance
self.case_sensitive = False
super(FormulaResponse, self).__init__(*args, **kwargs)
......@@ -2433,7 +2434,7 @@ class ChoiceTextResponse(LoncapaResponse):
input_name = child.get('name')
# Contextualize the tolerance to value.
tolerance = contextualize_text(
child.get('tolerance', '0'),
child.get('tolerance', default_tolerance),
context
)
# Add the answer and tolerance information for the current
......@@ -2662,7 +2663,7 @@ class ChoiceTextResponse(LoncapaResponse):
correct_ans = params['answer']
# Set the tolerance to '0' if it was not specified in the xml
tolerance = params.get('tolerance', '0')
tolerance = params.get('tolerance', default_tolerance)
# Make sure that the staff answer is a valid number
try:
correct_ans = complex(correct_ans)
......
......@@ -182,7 +182,10 @@ class NumericalResponseXMLFactory(ResponseXMLFactory):
response_element = etree.Element('numericalresponse')
if answer:
response_element.set('answer', str(answer))
if isinstance(answer, float):
response_element.set('answer', repr(answer))
else:
response_element.set('answer', str(answer))
if tolerance:
responseparam_element = etree.SubElement(response_element, 'responseparam')
......
......@@ -56,13 +56,11 @@ class ResponseTest(unittest.TestCase):
def assert_multiple_grade(self, problem, correct_answers, incorrect_answers):
for input_str in correct_answers:
result = problem.grade_answers({'1_2_1': input_str}).get_correctness('1_2_1')
self.assertEqual(result, 'correct',
msg="%s should be marked correct" % str(input_str))
self.assertEqual(result, 'correct')
for input_str in incorrect_answers:
result = problem.grade_answers({'1_2_1': input_str}).get_correctness('1_2_1')
self.assertEqual(result, 'incorrect',
msg="%s should be marked incorrect" % str(input_str))
self.assertEqual(result, 'incorrect')
def _get_random_number_code(self):
"""Returns code to be used to generate a random result."""
......@@ -1070,6 +1068,27 @@ class NumericalResponseTest(ResponseTest):
incorrect_responses = ["", "4.5", "3.5", "0"]
self.assert_multiple_grade(problem, correct_responses, incorrect_responses)
def test_floats(self):
"""
Default tolerance for all responsetypes is 1e-3%.
"""
problem_setup = [
#[given_asnwer, [list of correct responses], [list of incorrect responses]]
[1, ["1"], ["1.1"],],
[2.0, ["2.0"], ["1.0"],],
[4, ["4.0", "4.00004"], ["4.00005"]],
[0.00016, ["1.6*10^-4"], [""]],
[0.000016, ["1.6*10^-5"], ["0.000165"]],
[1.9e24, ["1.9*10^24"], ["1.9001*10^24"]],
[2e-15, ["2*10^-15"], [""]],
[3141592653589793238., ["3141592653589793115."], [""]],
[0.1234567, ["0.123456", "0.1234561"], ["0.123451"]],
[1e-5, ["1e-5", "1.0e-5"], ["-1e-5", "2*1e-5"]],
]
for given_answer, correct_responses, incorrect_responses in problem_setup:
problem = self.build_problem(answer=given_answer)
self.assert_multiple_grade(problem, correct_responses, incorrect_responses)
def test_grade_with_script(self):
script_text = "computed_response = math.sqrt(4)"
problem = self.build_problem(answer="$computed_response", script=script_text)
......
......@@ -4,16 +4,28 @@ from cmath import isinf
#-----------------------------------------------------------------------------
#
# Utility functions used in CAPA responsetypes
default_tolerance = '0.001%'
def compare_with_tolerance(v1, v2, tol):
''' Compare v1 to v2 with maximum tolerance tol
def compare_with_tolerance(v1, v2, tol=default_tolerance):
'''
Compare v1 to v2 with maximum tolerance tol.
tol is relative if it ends in %; otherwise, it is absolute
- v1 : student result (number)
- v2 : instructor result (number)
- v1 : student result (float complex number)
- v2 : instructor result (float complex number)
- tol : tolerance (string representing a number)
Default tolerance of 1e-3% is added to compare two floats for near-equality
(to handle machine representation errors).
It is relative, as the acceptable difference between two floats depends on the magnitude of the floats.
(http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/)
Examples:
In [183]: 0.000016 - 1.6*10**-5
Out[183]: -3.3881317890172014e-21
In [212]: 1.9e24 - 1.9*10**24
Out[212]: 268435456.0
'''
relative = tol.endswith('%')
if relative:
......@@ -28,6 +40,8 @@ def compare_with_tolerance(v1, v2, tol):
# `inf <= inf` which is a fail. Instead, compare directly.
return v1 == v2
else:
# v1 and v2 are, in general, complex numbers:
# there are some notes about backward compatibility issue: see responsetypes.get_staff_ans()).
return abs(v1 - v2) <= tolerance
......
......@@ -3,7 +3,7 @@ class @MarkdownEditingDescriptor extends XModule.Descriptor
@multipleChoiceTemplate : "( ) incorrect\n( ) incorrect\n(x) correct\n"
@checkboxChoiceTemplate: "[x] correct\n[ ] incorrect\n[x] correct\n"
@stringInputTemplate: "= answer\n"
@numberInputTemplate: "= answer +- x%\n"
@numberInputTemplate: "= answer +- 0.001%\n"
@selectTemplate: "[[incorrect, (correct), incorrect]]\n"
@headerTemplate: "Header\n=====\n"
@explanationTemplate: "[explanation]\nShort explanation\n[explanation]\n"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment